1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 
22 #include "db.h"
23 #include "log.h"
24 #include "dbcache.h"
25 #include "zbxserver.h"
26 #include "template.h"
27 
get_template_names(const zbx_vector_uint64_t * templateids)28 static char	*get_template_names(const zbx_vector_uint64_t *templateids)
29 {
30 	DB_RESULT	result;
31 	DB_ROW		row;
32 	char		*sql = NULL, *template_names = NULL;
33 	size_t		sql_alloc = 256, sql_offset=0, tmp_alloc = 64, tmp_offset = 0;
34 
35 	sql = zbx_malloc(sql, sql_alloc);
36 	template_names = zbx_malloc(template_names, tmp_alloc);
37 
38 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
39 			"select host"
40 			" from hosts"
41 			" where");
42 
43 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
44 			templateids->values, templateids->values_num);
45 
46 	result = DBselect("%s", sql);
47 
48 	while (NULL != (row = DBfetch(result)))
49 		zbx_snprintf_alloc(&template_names, &tmp_alloc, &tmp_offset, "\"%s\", ", row[0]);
50 
51 	template_names[tmp_offset - 2] = '\0';
52 
53 	DBfree_result(result);
54 	zbx_free(sql);
55 
56 	return template_names;
57 }
58 
59 /******************************************************************************
60  *                                                                            *
61  * Function: DBget_screenitems_by_resource_types_ids                          *
62  *                                                                            *
63  * Description: gets a vector of screen item identifiers used with the        *
64  *              specified resource types and identifiers                      *
65  *                                                                            *
66  * Parameters: screen_itemids - [OUT] the screen item identifiers             *
67  *             types          - [IN] an array of resource types               *
68  *             types_num      - [IN] the number of values in types array      *
69  *             resourceids    - [IN] the resource identifiers                 *
70  *                                                                            *
71  ******************************************************************************/
DBget_screenitems_by_resource_types_ids(zbx_vector_uint64_t * screen_itemids,const zbx_uint64_t * types,int types_num,const zbx_vector_uint64_t * resourceids)72 static void	DBget_screenitems_by_resource_types_ids(zbx_vector_uint64_t *screen_itemids, const zbx_uint64_t *types,
73 		int types_num, const zbx_vector_uint64_t *resourceids)
74 {
75 	char	*sql = NULL;
76 	size_t	sql_alloc = 0, sql_offset = 0;
77 
78 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select distinct screenitemid from screens_items where");
79 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "resourcetype", types, types_num);
80 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and");
81 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "resourceid", resourceids->values,
82 			resourceids->values_num);
83 
84 	DBselect_uint64(sql, screen_itemids);
85 
86 	zbx_free(sql);
87 
88 	zbx_vector_uint64_sort(screen_itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
89 }
90 
91 /******************************************************************************
92  *                                                                            *
93  * Function: DBget_profiles_by_source_idxs_values                             *
94  *                                                                            *
95  * Description: gets a vector of profile identifiers used with the specified  *
96  *              source, indexes and value identifiers                         *
97  *                                                                            *
98  * Parameters: profileids - [OUT] the screen item identifiers                 *
99  *             source     - [IN] the source                                   *
100  *             idxs       - [IN] an array of index values                     *
101  *             idxs_num   - [IN] the number of values in idxs array           *
102  *             value_ids  - [IN] the resource identifiers                     *
103  *                                                                            *
104  ******************************************************************************/
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)105 static void	DBget_profiles_by_source_idxs_values(zbx_vector_uint64_t *profileids, const char *source,
106 		const char **idxs, int idxs_num, zbx_vector_uint64_t *value_ids)
107 {
108 	char	*sql = NULL;
109 	size_t	sql_alloc = 0, sql_offset = 0;
110 
111 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select distinct profileid from profiles where");
112 
113 	if (NULL != source)
114 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " source='%s' and", source);
115 
116 	if (0 != idxs_num)
117 	{
118 		DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "idx", idxs, idxs_num);
119 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and");
120 	}
121 
122 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "value_id", value_ids->values, value_ids->values_num);
123 
124 	DBselect_uint64(sql, profileids);
125 
126 	zbx_free(sql);
127 
128 	zbx_vector_uint64_sort(profileids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
129 }
130 
131 /******************************************************************************
132  *                                                                            *
133  * Function: DBget_sysmapelements_by_element_type_ids                         *
134  *                                                                            *
135  * Description: gets a vector of sysmap element identifiers used with the     *
136  *              specified element type and identifiers                        *
137  *                                                                            *
138  * Parameters: selementids - [OUT] the sysmap element identifiers             *
139  *             elementtype - [IN] the element type                            *
140  *             elementids  - [IN] the element identifiers                     *
141  *                                                                            *
142  ******************************************************************************/
DBget_sysmapelements_by_element_type_ids(zbx_vector_uint64_t * selementids,int elementtype,zbx_vector_uint64_t * elementids)143 static void	DBget_sysmapelements_by_element_type_ids(zbx_vector_uint64_t *selementids, int elementtype,
144 		zbx_vector_uint64_t *elementids)
145 {
146 	char	*sql = NULL;
147 	size_t	sql_alloc = 0, sql_offset = 0;
148 
149 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
150 			"select distinct selementid"
151 			" from sysmaps_elements"
152 			" where elementtype=%d"
153 				" and",
154 			elementtype);
155 
156 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "elementid", elementids->values, elementids->values_num);
157 	DBselect_uint64(sql, selementids);
158 
159 	zbx_free(sql);
160 
161 	zbx_vector_uint64_sort(selementids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
162 }
163 
164 /******************************************************************************
165  *                                                                            *
166  * Function: validate_linked_templates                                        *
167  *                                                                            *
168  * Description: Check collisions between linked templates                     *
169  *                                                                            *
170  * Parameters: templateids - [IN] array of template IDs                       *
171  *                                                                            *
172  * Return value: SUCCEED if no collisions found                               *
173  *                                                                            *
174  * Author: Alexander Vladishev                                                *
175  *                                                                            *
176  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
177  *                                                                            *
178  ******************************************************************************/
validate_linked_templates(const zbx_vector_uint64_t * templateids,char * error,size_t max_error_len)179 static int	validate_linked_templates(const zbx_vector_uint64_t *templateids, char *error, size_t max_error_len)
180 {
181 	const char	*__function_name = "validate_linked_templates";
182 
183 	DB_RESULT	result;
184 	DB_ROW		row;
185 	char		*sql = NULL;
186 	size_t		sql_alloc = 256, sql_offset;
187 	int		ret = SUCCEED;
188 
189 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
190 
191 	if (0 == templateids->values_num)
192 		goto out;
193 
194 	sql = zbx_malloc(sql, sql_alloc);
195 
196 	/* items */
197 	if (SUCCEED == ret && 1 < templateids->values_num)
198 	{
199 		sql_offset = 0;
200 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
201 				"select key_,count(*)"
202 				" from items"
203 				" where");
204 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
205 				templateids->values, templateids->values_num);
206 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
207 				" group by key_"
208 				" having count(*)>1");
209 
210 		result = DBselectN(sql, 1);
211 
212 		if (NULL != (row = DBfetch(result)))
213 		{
214 			ret = FAIL;
215 			zbx_snprintf(error, max_error_len, "conflicting item key \"%s\" found", row[0]);
216 		}
217 		DBfree_result(result);
218 	}
219 
220 	/* trigger expressions */
221 	if (SUCCEED == ret)
222 	{
223 		sql_offset = 0;
224 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
225 				"select t1.description,h2.host"
226 				" from items i1,functions f1,triggers t1,functions f2,items i2,hosts h2"
227 				" where i1.itemid=f1.itemid"
228 					" and f1.triggerid=t1.triggerid"
229 					" and t1.triggerid=f2.triggerid"
230 					" and f2.itemid=i2.itemid"
231 					" and i2.hostid=h2.hostid"
232 					" and h2.status=%d"
233 					" and",
234 				HOST_STATUS_TEMPLATE);
235 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i1.hostid",
236 				templateids->values, templateids->values_num);
237 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
238 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i2.hostid",
239 				templateids->values, templateids->values_num);
240 
241 		result = DBselectN(sql, 1);
242 
243 		if (NULL != (row = DBfetch(result)))
244 		{
245 			ret = FAIL;
246 			zbx_snprintf(error, max_error_len,
247 					"trigger \"%s\" has items from template \"%s\"",
248 					row[0], row[1]);
249 		}
250 		DBfree_result(result);
251 	}
252 
253 	/* trigger dependencies */
254 	if (SUCCEED == ret)
255 	{
256 		sql_offset = 0;
257 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
258 				/* don't remove "description2 and host2" aliases, the ORACLE needs them */
259 				"select t1.description,h1.host,t2.description as description2,h2.host as host2"
260 				" from trigger_depends td,triggers t1,functions f1,items i1,hosts h1,"
261 					"triggers t2,functions f2,items i2,hosts h2"
262 				" where td.triggerid_down=t1.triggerid"
263 					" and t1.triggerid=f1.triggerid"
264 					" and f1.itemid=i1.itemid"
265 					" and i1.hostid=h1.hostid"
266 					" and td.triggerid_up=t2.triggerid"
267 					" and t2.triggerid=f2.triggerid"
268 					" and f2.itemid=i2.itemid"
269 					" and i2.hostid=h2.hostid"
270 					" and");
271 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i1.hostid",
272 				templateids->values, templateids->values_num);
273 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
274 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i2.hostid",
275 				templateids->values, templateids->values_num);
276 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and h2.status=%d", HOST_STATUS_TEMPLATE);
277 
278 		result = DBselectN(sql, 1);
279 
280 		if (NULL != (row = DBfetch(result)))
281 		{
282 			ret = FAIL;
283 			zbx_snprintf(error, max_error_len,
284 					"trigger \"%s\" in template \"%s\""
285 					" has dependency from trigger \"%s\" in template \"%s\"",
286 					row[0], row[1], row[2], row[3]);
287 		}
288 		DBfree_result(result);
289 	}
290 
291 	/* graphs */
292 	if (SUCCEED == ret && 1 < templateids->values_num)
293 	{
294 		zbx_vector_uint64_t	graphids;
295 
296 		zbx_vector_uint64_create(&graphids);
297 
298 		/* select all linked graphs */
299 		sql_offset = 0;
300 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
301 				"select distinct gi.graphid"
302 				" from graphs_items gi,items i"
303 				" where gi.itemid=i.itemid"
304 					" and");
305 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.hostid",
306 				templateids->values, templateids->values_num);
307 
308 		DBselect_uint64(sql, &graphids);
309 
310 		/* check for names */
311 		if (0 != graphids.values_num)
312 		{
313 			sql_offset = 0;
314 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
315 					"select name,count(*)"
316 					" from graphs"
317 					" where");
318 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "graphid",
319 					graphids.values, graphids.values_num);
320 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
321 					" group by name"
322 					" having count(*)>1");
323 
324 			result = DBselect("%s", sql);
325 
326 			if (NULL != (row = DBfetch(result)))
327 			{
328 				ret = FAIL;
329 				zbx_snprintf(error, max_error_len,
330 						"template with graph \"%s\" already linked to the host", row[0]);
331 			}
332 			DBfree_result(result);
333 		}
334 
335 		zbx_vector_uint64_destroy(&graphids);
336 	}
337 
338 	/* httptests */
339 	if (SUCCEED == ret && 1 < templateids->values_num)
340 	{
341 		sql_offset = 0;
342 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
343 				"select name,count(*)"
344 				" from httptest"
345 				" where");
346 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
347 				templateids->values, templateids->values_num);
348 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
349 				" group by name"
350 				" having count(*)>1");
351 
352 		result = DBselectN(sql, 1);
353 
354 		if (NULL != (row = DBfetch(result)))
355 		{
356 			ret = FAIL;
357 			zbx_snprintf(error, max_error_len,
358 					"template with web scenario \"%s\" already linked to the host", row[0]);
359 		}
360 		DBfree_result(result);
361 	}
362 
363 	zbx_free(sql);
364 out:
365 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
366 
367 	return ret;
368 }
369 
370 /******************************************************************************
371  *                                                                            *
372  * Function: DBcmp_triggers                                                   *
373  *                                                                            *
374  * Purpose: compare two triggers                                              *
375  *                                                                            *
376  * Parameters: triggerid1 - first trigger identificator from database         *
377  *             triggerid2 - second trigger identificator from database        *
378  *                                                                            *
379  * Return value: SUCCEED - if triggers coincide                               *
380  *                                                                            *
381  * Author: Eugene Grigorjev                                                   *
382  *                                                                            *
383  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
384  *                                                                            *
385  ******************************************************************************/
DBcmp_triggers(zbx_uint64_t triggerid1,const char * expression1,zbx_uint64_t triggerid2,const char * expression2)386 static int	DBcmp_triggers(zbx_uint64_t triggerid1, const char *expression1,
387 		zbx_uint64_t triggerid2, const char *expression2)
388 {
389 	DB_RESULT	result;
390 	DB_ROW		row;
391 	char		*search = NULL,
392 			*replace = NULL,
393 			*old_expr = NULL,
394 			*expr = NULL;
395 	int		res = SUCCEED;
396 
397 	expr = strdup(expression2);
398 
399 	result = DBselect(
400 			"select f1.functionid,f2.functionid"
401 			" from functions f1,functions f2,items i1,items i2"
402 			" where f1.function=f2.function"
403 				" and f1.parameter=f2.parameter"
404 				" and i1.key_=i2.key_"
405 				" and i1.itemid=f1.itemid"
406 				" and i2.itemid=f2.itemid"
407 				" and f1.triggerid=" ZBX_FS_UI64
408 				" and f2.triggerid=" ZBX_FS_UI64,
409 				triggerid1, triggerid2);
410 
411 	while (NULL != (row = DBfetch(result)))
412 	{
413 		search = zbx_dsprintf(NULL, "{%s}", row[1]);
414 		replace = zbx_dsprintf(NULL, "{%s}", row[0]);
415 
416 		old_expr = expr;
417 		expr = string_replace(old_expr, search, replace);
418 		zbx_free(old_expr);
419 
420 		zbx_free(replace);
421 		zbx_free(search);
422 	}
423 	DBfree_result(result);
424 
425 	if (0 != strcmp(expression1, expr))
426 		res = FAIL;
427 
428 	zbx_free(expr);
429 
430 	return res;
431 }
432 
433 /******************************************************************************
434  *                                                                            *
435  * Function: validate_inventory_links                                         *
436  *                                                                            *
437  * Description: Check collisions in item inventory links                      *
438  *                                                                            *
439  * Parameters: hostid      - [IN] host identificator from database            *
440  *             templateids - [IN] array of template IDs                       *
441  *                                                                            *
442  * Return value: SUCCEED if no collisions found                               *
443  *                                                                            *
444  * Author: Alexander Vladishev                                                *
445  *                                                                            *
446  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
447  *                                                                            *
448  ******************************************************************************/
validate_inventory_links(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids,char * error,size_t max_error_len)449 static int	validate_inventory_links(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids,
450 		char *error, size_t max_error_len)
451 {
452 	const char	*__function_name = "validate_inventory_links";
453 	DB_RESULT	result;
454 	DB_ROW		row;
455 	char		*sql = NULL;
456 	size_t		sql_alloc = 512, sql_offset;
457 	int		ret = SUCCEED;
458 
459 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
460 
461 	sql = zbx_malloc(sql, sql_alloc);
462 
463 	sql_offset = 0;
464 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
465 			"select inventory_link,count(*)"
466 			" from items"
467 			" where inventory_link<>0"
468 				" and");
469 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
470 			templateids->values, templateids->values_num);
471 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
472 			" group by inventory_link"
473 			" having count(*)>1");
474 
475 	result = DBselectN(sql, 1);
476 
477 	if (NULL != (row = DBfetch(result)))
478 	{
479 		ret = FAIL;
480 		zbx_strlcpy(error, "two items cannot populate one host inventory field", max_error_len);
481 	}
482 	DBfree_result(result);
483 
484 	if (FAIL == ret)
485 		goto out;
486 
487 	sql_offset = 0;
488 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
489 			"select ti.itemid"
490 			" from items ti,items i"
491 			" where ti.key_<>i.key_"
492 				" and ti.inventory_link=i.inventory_link"
493 				" and");
494 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid",
495 			templateids->values, templateids->values_num);
496 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
497 				" and i.hostid=" ZBX_FS_UI64
498 				" and ti.inventory_link<>0"
499 				" and not exists ("
500 					"select *"
501 					" from items",
502 				hostid);
503 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " where");
504 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "items.hostid",
505 			templateids->values, templateids->values_num);
506 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
507 						" and items.key_=i.key_"
508 					")");
509 
510 	result = DBselectN(sql, 1);
511 
512 	if (NULL != (row = DBfetch(result)))
513 	{
514 		ret = FAIL;
515 		zbx_strlcpy(error, "two items cannot populate one host inventory field", max_error_len);
516 	}
517 	DBfree_result(result);
518 out:
519 	zbx_free(sql);
520 
521 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
522 
523 	return ret;
524 }
525 
526 /******************************************************************************
527  *                                                                            *
528  * Function: validate_httptests                                               *
529  *                                                                            *
530  * Description: checking collisions on linking of web scenarios               *
531  *                                                                            *
532  * Parameters: hostid      - [IN] host identificator from database            *
533  *             templateids - [IN] array of template IDs                       *
534  *                                                                            *
535  * Return value: SUCCEED if no collisions found                               *
536  *                                                                            *
537  * Author: Alexander Vladishev                                                *
538  *                                                                            *
539  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
540  *                                                                            *
541  ******************************************************************************/
validate_httptests(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids,char * error,size_t max_error_len)542 static int	validate_httptests(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids,
543 		char *error, size_t max_error_len)
544 {
545 	const char	*__function_name = "validate_httptests";
546 	DB_RESULT	tresult;
547 	DB_RESULT	sresult;
548 	DB_ROW		trow;
549 	char		*sql = NULL;
550 	size_t		sql_alloc = 512, sql_offset = 0;
551 	int		ret = SUCCEED;
552 	zbx_uint64_t	t_httptestid, h_httptestid;
553 
554 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
555 
556 	sql = zbx_malloc(sql, sql_alloc);
557 
558 	/* selects web scenarios from templates and host with identical names */
559 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
560 			"select t.httptestid,t.name,h.httptestid"
561 			" from httptest t"
562 				" inner join httptest h"
563 					" on h.name=t.name"
564 						" and h.hostid=" ZBX_FS_UI64
565 			" where", hostid);
566 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.hostid", templateids->values, templateids->values_num);
567 
568 	tresult = DBselect("%s", sql);
569 
570 	while (NULL != (trow = DBfetch(tresult)))
571 	{
572 		ZBX_STR2UINT64(t_httptestid, trow[0]);
573 		ZBX_STR2UINT64(h_httptestid, trow[2]);
574 
575 		sql_offset = 0;
576 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
577 				/* don't remove "h_httpstepid" alias, the ORACLE needs it */
578 				"select t.httpstepid,h.httpstepid as h_httpstepid"
579 				" from httpstep t"
580 					" left join httpstep h"
581 						" on h.httptestid=" ZBX_FS_UI64
582 							" and h.no=t.no"
583 							" and h.name=t.name"
584 				" where t.httptestid=" ZBX_FS_UI64
585 					" and h.httpstepid is null"
586 				" union "
587 				"select t.httpstepid,h.httpstepid as h_httpstepid"
588 				" from httpstep h"
589 					" left outer join httpstep t"
590 						" on t.httptestid=" ZBX_FS_UI64
591 							" and t.no=h.no"
592 							" and t.name=h.name"
593 				" where h.httptestid=" ZBX_FS_UI64
594 					" and t.httpstepid is null",
595 				h_httptestid, t_httptestid, t_httptestid, h_httptestid);
596 
597 		sresult = DBselectN(sql, 1);
598 
599 		if (NULL != DBfetch(sresult))
600 		{
601 			ret = FAIL;
602 			zbx_snprintf(error, max_error_len,
603 					"web scenario \"%s\" already exists on the host (steps are not identical)",
604 					trow[1]);
605 		}
606 		DBfree_result(sresult);
607 
608 		if (SUCCEED != ret)
609 			break;
610 	}
611 	DBfree_result(tresult);
612 
613 	zbx_free(sql);
614 
615 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
616 
617 	return ret;
618 }
619 
DBget_graphitems(const char * sql,ZBX_GRAPH_ITEMS ** gitems,size_t * gitems_alloc,size_t * gitems_num)620 static void	DBget_graphitems(const char *sql, ZBX_GRAPH_ITEMS **gitems, size_t *gitems_alloc, size_t *gitems_num)
621 {
622 	const char	*__function_name = "DBget_graphitems";
623 	DB_RESULT	result;
624 	DB_ROW		row;
625 	ZBX_GRAPH_ITEMS	*gitem;
626 
627 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
628 
629 	*gitems_num = 0;
630 
631 	result = DBselect("%s", sql);
632 
633 	while (NULL != (row = DBfetch(result)))
634 	{
635 		if (*gitems_alloc == *gitems_num)
636 		{
637 			*gitems_alloc += 16;
638 			*gitems = zbx_realloc(*gitems, *gitems_alloc * sizeof(ZBX_GRAPH_ITEMS));
639 		}
640 
641 		gitem = &(*gitems)[*gitems_num];
642 
643 		ZBX_STR2UINT64(gitem->gitemid, row[0]);
644 		ZBX_STR2UINT64(gitem->itemid, row[1]);
645 		zbx_strlcpy(gitem->key, row[2], sizeof(gitem->key));
646 		gitem->drawtype = atoi(row[3]);
647 		gitem->sortorder = atoi(row[4]);
648 		zbx_strlcpy(gitem->color, row[5], sizeof(gitem->color));
649 		gitem->yaxisside = atoi(row[6]);
650 		gitem->calc_fnc = atoi(row[7]);
651 		gitem->type = atoi(row[8]);
652 		gitem->flags = (unsigned char)atoi(row[9]);
653 
654 		zabbix_log(LOG_LEVEL_DEBUG, "%s() [%d] itemid:" ZBX_FS_UI64 " key:'%s'",
655 				__function_name, *gitems_num, gitem->itemid, gitem->key);
656 
657 		(*gitems_num)++;
658 	}
659 	DBfree_result(result);
660 
661 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
662 }
663 
664 /******************************************************************************
665  *                                                                            *
666  * Function: DBcmp_graphitems                                                 *
667  *                                                                            *
668  * Purpose: Compare graph items from two graphs                               *
669  *                                                                            *
670  * Parameters: gitems1     - [IN] first graph items, sorted by itemid         *
671  *             gitems1_num - [IN] number of first graph items                 *
672  *             gitems2     - [IN] second graph items, sorted by itemid        *
673  *             gitems2_num - [IN] number of second graph items                *
674  *                                                                            *
675  * Return value: SUCCEED if graph items coincide                              *
676  *                                                                            *
677  * Author: Alexander Vladishev                                                *
678  *                                                                            *
679  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
680  *                                                                            *
681  ******************************************************************************/
DBcmp_graphitems(ZBX_GRAPH_ITEMS * gitems1,int gitems1_num,ZBX_GRAPH_ITEMS * gitems2,int gitems2_num)682 static int	DBcmp_graphitems(ZBX_GRAPH_ITEMS *gitems1, int gitems1_num,
683 		ZBX_GRAPH_ITEMS *gitems2, int gitems2_num)
684 {
685 	const char	*__function_name = "DBcmp_graphitems";
686 	int		res = FAIL, i;
687 
688 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
689 
690 	if (gitems1_num != gitems2_num)
691 		goto clean;
692 
693 	for (i = 0; i < gitems1_num; i++)
694 		if (0 != strcmp(gitems1[i].key, gitems2[i].key))
695 			goto clean;
696 
697 	res = SUCCEED;
698 clean:
699 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res));
700 
701 	return res;
702 }
703 
704 /******************************************************************************
705  *                                                                            *
706  * Function: validate_host                                                    *
707  *                                                                            *
708  * Description: Check collisions between host and linked template             *
709  *                                                                            *
710  * Parameters: hostid      - [IN] host identificator from database            *
711  *             templateids - [IN] array of template IDs                       *
712  *                                                                            *
713  * Return value: SUCCEED if no collisions found                               *
714  *                                                                            *
715  * Author: Alexander Vladishev                                                *
716  *                                                                            *
717  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
718  *                                                                            *
719  ******************************************************************************/
validate_host(zbx_uint64_t hostid,zbx_vector_uint64_t * templateids,char * error,size_t max_error_len)720 static int	validate_host(zbx_uint64_t hostid, zbx_vector_uint64_t *templateids, char *error, size_t max_error_len)
721 {
722 	const char	*__function_name = "validate_host";
723 	DB_RESULT	tresult;
724 	DB_RESULT	hresult;
725 	DB_ROW		trow;
726 	DB_ROW		hrow;
727 	char		*sql = NULL, *name_esc;
728 	size_t		sql_alloc = 256, sql_offset;
729 	ZBX_GRAPH_ITEMS	*gitems = NULL, *chd_gitems = NULL;
730 	size_t		gitems_alloc = 0, gitems_num = 0,
731 			chd_gitems_alloc = 0, chd_gitems_num = 0;
732 	int		ret = SUCCEED, i;
733 	zbx_uint64_t	graphid, interfaceids[INTERFACE_TYPE_COUNT];
734 	unsigned char	t_flags, h_flags, type;
735 
736 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
737 
738 	if (SUCCEED != (ret = validate_inventory_links(hostid, templateids, error, max_error_len)))
739 		goto out;
740 
741 	if (SUCCEED != (ret = validate_httptests(hostid, templateids, error, max_error_len)))
742 		goto out;
743 
744 	sql = zbx_malloc(sql, sql_alloc);
745 
746 	sql_offset = 0;
747 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
748 			"select distinct g.graphid,g.name,g.flags"
749 			" from graphs g,graphs_items gi,items i"
750 			" where g.graphid=gi.graphid"
751 				" and gi.itemid=i.itemid"
752 				" and");
753 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.hostid", templateids->values, templateids->values_num);
754 
755 	tresult = DBselect("%s", sql);
756 
757 	while (SUCCEED == ret && NULL != (trow = DBfetch(tresult)))
758 	{
759 		ZBX_STR2UINT64(graphid, trow[0]);
760 		t_flags = (unsigned char)atoi(trow[2]);
761 
762 		sql_offset = 0;
763 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
764 				"select 0,0,i.key_,gi.drawtype,gi.sortorder,gi.color,gi.yaxisside,gi.calc_fnc,"
765 					"gi.type,i.flags"
766 				" from graphs_items gi,items i"
767 				" where gi.itemid=i.itemid"
768 					" and gi.graphid=" ZBX_FS_UI64
769 				" order by i.key_",
770 				graphid);
771 
772 		DBget_graphitems(sql, &gitems, &gitems_alloc, &gitems_num);
773 
774 		name_esc = DBdyn_escape_string(trow[1]);
775 
776 		hresult = DBselect(
777 				"select distinct g.graphid,g.flags"
778 				" from graphs g,graphs_items gi,items i"
779 				" where g.graphid=gi.graphid"
780 					" and gi.itemid=i.itemid"
781 					" and i.hostid=" ZBX_FS_UI64
782 					" and g.name='%s'"
783 					" and g.templateid is null",
784 				hostid, name_esc);
785 
786 		zbx_free(name_esc);
787 
788 		/* compare graphs */
789 		while (NULL != (hrow = DBfetch(hresult)))
790 		{
791 			ZBX_STR2UINT64(graphid, hrow[0]);
792 			h_flags = (unsigned char)atoi(hrow[1]);
793 
794 			if (t_flags != h_flags)
795 			{
796 				ret = FAIL;
797 				zbx_snprintf(error, max_error_len,
798 						"graph prototype and real graph \"%s\" have the same name", trow[1]);
799 				break;
800 			}
801 
802 			sql_offset = 0;
803 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
804 					"select gi.gitemid,i.itemid,i.key_,gi.drawtype,gi.sortorder,gi.color,"
805 						"gi.yaxisside,gi.calc_fnc,gi.type,i.flags"
806 					" from graphs_items gi,items i"
807 					" where gi.itemid=i.itemid"
808 						" and gi.graphid=" ZBX_FS_UI64
809 					" order by i.key_",
810 					graphid);
811 
812 			DBget_graphitems(sql, &chd_gitems, &chd_gitems_alloc, &chd_gitems_num);
813 
814 			if (SUCCEED != DBcmp_graphitems(gitems, gitems_num, chd_gitems, chd_gitems_num))
815 			{
816 				ret = FAIL;
817 				zbx_snprintf(error, max_error_len,
818 						"graph \"%s\" already exists on the host (items are not identical)",
819 						trow[1]);
820 				break;
821 			}
822 		}
823 		DBfree_result(hresult);
824 	}
825 	DBfree_result(tresult);
826 
827 	if (SUCCEED == ret)
828 	{
829 		sql_offset = 0;
830 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
831 				"select i.key_"
832 				" from items i,items t"
833 				" where i.key_=t.key_"
834 					" and i.flags<>t.flags"
835 					" and i.hostid=" ZBX_FS_UI64
836 					" and",
837 				hostid);
838 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.hostid",
839 				templateids->values, templateids->values_num);
840 
841 		tresult = DBselectN(sql, 1);
842 
843 		if (NULL != (trow = DBfetch(tresult)))
844 		{
845 			ret = FAIL;
846 			zbx_snprintf(error, max_error_len,
847 					"item prototype and real item \"%s\" have the same key", trow[0]);
848 		}
849 		DBfree_result(tresult);
850 	}
851 
852 	/* interfaces */
853 	if (SUCCEED == ret)
854 	{
855 		memset(&interfaceids, 0, sizeof(interfaceids));
856 
857 		tresult = DBselect(
858 				"select type,interfaceid"
859 				" from interface"
860 				" where hostid=" ZBX_FS_UI64
861 					" and type in (%d,%d,%d,%d)"
862 					" and main=1",
863 				hostid, INTERFACE_TYPE_AGENT, INTERFACE_TYPE_SNMP,
864 				INTERFACE_TYPE_IPMI, INTERFACE_TYPE_JMX);
865 
866 		while (NULL != (trow = DBfetch(tresult)))
867 		{
868 			type = (unsigned char)atoi(trow[0]);
869 			ZBX_STR2UINT64(interfaceids[type - 1], trow[1]);
870 		}
871 		DBfree_result(tresult);
872 
873 		sql_offset = 0;
874 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
875 				"select distinct type"
876 				" from items"
877 				" where type not in (%d,%d,%d,%d,%d,%d,%d)"
878 					" and",
879 				ITEM_TYPE_TRAPPER, ITEM_TYPE_INTERNAL, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_AGGREGATE,
880 				ITEM_TYPE_HTTPTEST, ITEM_TYPE_DB_MONITOR, ITEM_TYPE_CALCULATED);
881 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
882 				templateids->values, templateids->values_num);
883 
884 		tresult = DBselect("%s", sql);
885 
886 		while (SUCCEED == ret && NULL != (trow = DBfetch(tresult)))
887 		{
888 			type = (unsigned char)atoi(trow[0]);
889 			type = get_interface_type_by_item_type(type);
890 
891 			if (INTERFACE_TYPE_ANY == type)
892 			{
893 				for (i = 0; INTERFACE_TYPE_COUNT > i; i++)
894 				{
895 					if (0 != interfaceids[i])
896 						break;
897 				}
898 
899 				if (INTERFACE_TYPE_COUNT == i)
900 				{
901 					zbx_strlcpy(error, "cannot find any interfaces on host", max_error_len);
902 					ret = FAIL;
903 				}
904 			}
905 			else if (0 == interfaceids[type - 1])
906 			{
907 				zbx_snprintf(error, max_error_len, "cannot find \"%s\" host interface",
908 						zbx_interface_type_string((zbx_interface_type_t)type));
909 				ret = FAIL;
910 			}
911 		}
912 		DBfree_result(tresult);
913 	}
914 
915 	zbx_free(sql);
916 	zbx_free(gitems);
917 	zbx_free(chd_gitems);
918 out:
919 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
920 
921 	return ret;
922 }
923 
924 /******************************************************************************
925  *                                                                            *
926  * Function: DBdelete_action_conditions                                       *
927  *                                                                            *
928  * Purpose: delete action conditions by condition type and id                 *
929  *                                                                            *
930  * Author: Alexander Vladishev                                                *
931  *                                                                            *
932  ******************************************************************************/
DBdelete_action_conditions(int conditiontype,zbx_uint64_t elementid)933 static void	DBdelete_action_conditions(int conditiontype, zbx_uint64_t elementid)
934 {
935 	DB_RESULT		result;
936 	DB_ROW			row;
937 	zbx_uint64_t		id;
938 	zbx_vector_uint64_t	actionids, conditionids;
939 	char			*sql = NULL;
940 	size_t			sql_alloc = 0, sql_offset = 0;
941 
942 	zbx_vector_uint64_create(&actionids);
943 	zbx_vector_uint64_create(&conditionids);
944 
945 	/* disable actions */
946 	result = DBselect("select actionid,conditionid from conditions where conditiontype=%d and"
947 			" value='" ZBX_FS_UI64 "'", conditiontype, elementid);
948 
949 	while (NULL != (row = DBfetch(result)))
950 	{
951 		ZBX_STR2UINT64(id, row[0]);
952 		zbx_vector_uint64_append(&actionids, id);
953 
954 		ZBX_STR2UINT64(id, row[1]);
955 		zbx_vector_uint64_append(&conditionids, id);
956 	}
957 
958 	DBfree_result(result);
959 
960 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
961 
962 	if (0 != actionids.values_num)
963 	{
964 		zbx_vector_uint64_sort(&actionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
965 		zbx_vector_uint64_uniq(&actionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
966 
967 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update actions set status=%d where",
968 				ACTION_STATUS_DISABLED);
969 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "actionid", actionids.values,
970 				actionids.values_num);
971 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
972 	}
973 
974 	if (0 != conditionids.values_num)
975 	{
976 		zbx_vector_uint64_sort(&conditionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
977 
978 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from conditions where");
979 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "conditionid", conditionids.values,
980 				conditionids.values_num);
981 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
982 	}
983 
984 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
985 
986 	/* in ORACLE always present begin..end; */
987 	if (16 < sql_offset)
988 		DBexecute("%s", sql);
989 
990 	zbx_free(sql);
991 
992 	zbx_vector_uint64_destroy(&conditionids);
993 	zbx_vector_uint64_destroy(&actionids);
994 }
995 
996 /******************************************************************************
997  *                                                                            *
998  * Function: DBdelete_triggers                                                *
999  *                                                                            *
1000  * Purpose: delete trigger from database                                      *
1001  *                                                                            *
1002  * Parameters: triggerids - [IN] trigger identificators from database         *
1003  *                                                                            *
1004  ******************************************************************************/
DBdelete_triggers(zbx_vector_uint64_t * triggerids)1005 static void	DBdelete_triggers(zbx_vector_uint64_t *triggerids)
1006 {
1007 	char			*sql = NULL;
1008 	size_t			sql_alloc = 256, sql_offset;
1009 	int			i;
1010 	zbx_vector_uint64_t	profileids, selementids;
1011 	const char		*profile_idx = "web.events.filter.triggerid";
1012 
1013 	if (0 == triggerids->values_num)
1014 		return;
1015 
1016 	sql = zbx_malloc(sql, sql_alloc);
1017 
1018 	zbx_vector_uint64_create(&profileids);
1019 	zbx_vector_uint64_create(&selementids);
1020 
1021 	DBremove_triggers_from_itservices(triggerids->values, triggerids->values_num);
1022 
1023 	sql_offset = 0;
1024 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
1025 
1026 	DBget_sysmapelements_by_element_type_ids(&selementids, SYSMAP_ELEMENT_TYPE_TRIGGER, triggerids);
1027 	if (0 != selementids.values_num)
1028 	{
1029 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from sysmaps_elements where");
1030 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "selementid", selementids.values,
1031 				selementids.values_num);
1032 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
1033 	}
1034 
1035 	for (i = 0; i < triggerids->values_num; i++)
1036 		DBdelete_action_conditions(CONDITION_TYPE_TRIGGER, triggerids->values[i]);
1037 
1038 	DBget_profiles_by_source_idxs_values(&profileids, NULL, &profile_idx, 1, triggerids);
1039 	if (0 != profileids.values_num)
1040 	{
1041 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from profiles where");
1042 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "profileid", profileids.values,
1043 				profileids.values_num);
1044 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
1045 	}
1046 
1047 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
1048 			"delete from triggers"
1049 			" where");
1050 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid", triggerids->values, triggerids->values_num);
1051 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
1052 
1053 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
1054 
1055 	DBexecute("%s", sql);
1056 
1057 	zbx_vector_uint64_destroy(&selementids);
1058 	zbx_vector_uint64_destroy(&profileids);
1059 
1060 	zbx_free(sql);
1061 }
1062 
1063 /******************************************************************************
1064  *                                                                            *
1065  * Function: DBdelete_trigger_hierarchy                                       *
1066  *                                                                            *
1067  * Purpose: delete parent triggers and auto-created children from database    *
1068  *                                                                            *
1069  * Parameters: triggerids - [IN] trigger identificators from database         *
1070  *                                                                            *
1071  ******************************************************************************/
DBdelete_trigger_hierarchy(zbx_vector_uint64_t * triggerids)1072 static void	DBdelete_trigger_hierarchy(zbx_vector_uint64_t *triggerids)
1073 {
1074 	char			*sql = NULL;
1075 	size_t			sql_alloc = 256, sql_offset = 0;
1076 	zbx_vector_uint64_t	children_triggerids;
1077 
1078 	if (0 == triggerids->values_num)
1079 		return;
1080 
1081 	sql = zbx_malloc(sql, sql_alloc);
1082 
1083 	zbx_vector_uint64_create(&children_triggerids);
1084 
1085 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select distinct triggerid from trigger_discovery where");
1086 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "parent_triggerid", triggerids->values,
1087 			triggerids->values_num);
1088 
1089 	DBselect_uint64(sql, &children_triggerids);
1090 	zbx_vector_uint64_setdiff(triggerids, &children_triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1091 
1092 	DBdelete_triggers(&children_triggerids);
1093 	DBdelete_triggers(triggerids);
1094 
1095 	zbx_vector_uint64_destroy(&children_triggerids);
1096 
1097 	zbx_free(sql);
1098 }
1099 
1100 /******************************************************************************
1101  *                                                                            *
1102  * Function: DBdelete_triggers_by_itemids                                     *
1103  *                                                                            *
1104  * Purpose: delete triggers by itemid                                         *
1105  *                                                                            *
1106  * Parameters: itemids - [IN] item identificators from database               *
1107  *                                                                            *
1108  * Author: Eugene Grigorjev                                                   *
1109  *                                                                            *
1110  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
1111  *                                                                            *
1112  ******************************************************************************/
DBdelete_triggers_by_itemids(zbx_vector_uint64_t * itemids)1113 static void	DBdelete_triggers_by_itemids(zbx_vector_uint64_t *itemids)
1114 {
1115 	const char		*__function_name = "DBdelete_triggers_by_itemids";
1116 
1117 	char			*sql = NULL;
1118 	size_t			sql_alloc = 0, sql_offset = 0;
1119 	zbx_vector_uint64_t	triggerids;
1120 
1121 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __function_name, itemids->values_num);
1122 
1123 	if (0 == itemids->values_num)
1124 		goto out;
1125 
1126 	zbx_vector_uint64_create(&triggerids);
1127 
1128 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select distinct triggerid from functions where");
1129 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids->values, itemids->values_num);
1130 
1131 	DBselect_uint64(sql, &triggerids);
1132 
1133 	DBdelete_trigger_hierarchy(&triggerids);
1134 
1135 	zbx_vector_uint64_destroy(&triggerids);
1136 	zbx_free(sql);
1137 out:
1138 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1139 }
1140 
1141 /******************************************************************************
1142  *                                                                            *
1143  * Function: DBdelete_history_by_itemids                                      *
1144  *                                                                            *
1145  * Purpose: delete item history                                               *
1146  *                                                                            *
1147  * Parameters: itemids - [IN] item identificators from database               *
1148  *                                                                            *
1149  * Author: Eugene Grigorjev, Alexander Vladishev                              *
1150  *                                                                            *
1151  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
1152  *                                                                            *
1153  ******************************************************************************/
DBdelete_history_by_itemids(zbx_vector_uint64_t * itemids)1154 static void	DBdelete_history_by_itemids(zbx_vector_uint64_t *itemids)
1155 {
1156 	const char	*__function_name = "DBdelete_history_by_itemids";
1157 	int		i, j;
1158 	zbx_uint64_t	housekeeperid;
1159 	zbx_db_insert_t	db_insert;
1160 
1161 #define        ZBX_HISTORY_TABLES_COUNT        7
1162 	const char	*tables[ZBX_HISTORY_TABLES_COUNT] = {"history", "history_str", "history_uint", "history_log",
1163 			"history_text", "trends", "trends_uint"};
1164 
1165 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __function_name, itemids->values_num);
1166 
1167 	if (0 == itemids->values_num)
1168 		goto out;
1169 
1170 	housekeeperid = DBget_maxid_num("housekeeper", ZBX_HISTORY_TABLES_COUNT * itemids->values_num);
1171 
1172 	zbx_db_insert_prepare(&db_insert, "housekeeper", "housekeeperid", "tablename", "field", "value", NULL);
1173 
1174 	for (i = 0; i < itemids->values_num; i++)
1175 	{
1176 		for (j = 0; j < ZBX_HISTORY_TABLES_COUNT; j++)
1177 			zbx_db_insert_add_values(&db_insert, housekeeperid++, tables[j], "itemid", itemids->values[i]);
1178 	}
1179 
1180 	zbx_db_insert_execute(&db_insert);
1181 	zbx_db_insert_clean(&db_insert);
1182 out:
1183 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1184 }
1185 
1186 /******************************************************************************
1187  *                                                                            *
1188  * Function: DBdelete_graphs                                                  *
1189  *                                                                            *
1190  * Purpose: delete graph from database                                        *
1191  *                                                                            *
1192  * Parameters: graphids - [IN] array of graph id's from database              *
1193  *                                                                            *
1194  ******************************************************************************/
DBdelete_graphs(zbx_vector_uint64_t * graphids)1195 void	DBdelete_graphs(zbx_vector_uint64_t *graphids)
1196 {
1197 	const char		*__function_name = "DBdelete_graphs";
1198 
1199 	char			*sql = NULL;
1200 	size_t			sql_alloc = 256, sql_offset = 0;
1201 	zbx_vector_uint64_t	profileids, screen_itemids;
1202 	zbx_uint64_t		resource_type = SCREEN_RESOURCE_GRAPH;
1203 	const char		*profile_idx =  "web.favorite.graphids";
1204 
1205 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __function_name, graphids->values_num);
1206 
1207 	if (0 == graphids->values_num)
1208 		goto out;
1209 
1210 	sql = zbx_malloc(sql, sql_alloc);
1211 
1212 	zbx_vector_uint64_create(&profileids);
1213 	zbx_vector_uint64_create(&screen_itemids);
1214 
1215 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
1216 
1217 	/* delete from screens_items */
1218 	DBget_screenitems_by_resource_types_ids(&screen_itemids, &resource_type, 1, graphids);
1219 	if (0 != screen_itemids.values_num)
1220 	{
1221 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from screens_items where");
1222 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "screenitemid", screen_itemids.values,
1223 				screen_itemids.values_num);
1224 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
1225 	}
1226 
1227 	/* delete from profiles */
1228 	DBget_profiles_by_source_idxs_values(&profileids, "graphid", &profile_idx, 1, graphids);
1229 	if (0 != profileids.values_num)
1230 	{
1231 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from profiles where");
1232 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "profileid", profileids.values,
1233 				profileids.values_num);
1234 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
1235 	}
1236 
1237 	/* delete from graphs */
1238 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from graphs where");
1239 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "graphid", graphids->values, graphids->values_num);
1240 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
1241 
1242 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
1243 
1244 	DBexecute("%s", sql);
1245 
1246 	zbx_vector_uint64_destroy(&screen_itemids);
1247 	zbx_vector_uint64_destroy(&profileids);
1248 
1249 	zbx_free(sql);
1250 out:
1251 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1252 }
1253 
1254 /******************************************************************************
1255  *                                                                            *
1256  * Function: DBdelete_graph_hierarchy                                         *
1257  *                                                                            *
1258  * Purpose: delete parent graphs and auto-created children from database      *
1259  *                                                                            *
1260  * Parameters: graphids - [IN] array of graph id's from database              *
1261  *                                                                            *
1262  ******************************************************************************/
DBdelete_graph_hierarchy(zbx_vector_uint64_t * graphids)1263 static void	DBdelete_graph_hierarchy(zbx_vector_uint64_t *graphids)
1264 {
1265 	char			*sql = NULL;
1266 	size_t			sql_alloc = 256, sql_offset = 0;
1267 	zbx_vector_uint64_t	children_graphids;
1268 
1269 	if (0 == graphids->values_num)
1270 		return;
1271 
1272 	sql = zbx_malloc(sql, sql_alloc);
1273 
1274 	zbx_vector_uint64_create(&children_graphids);
1275 
1276 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select distinct graphid from graph_discovery where");
1277 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "parent_graphid", graphids->values,
1278 			graphids->values_num);
1279 
1280 	DBselect_uint64(sql, &children_graphids);
1281 	zbx_vector_uint64_setdiff(graphids, &children_graphids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1282 
1283 	DBdelete_graphs(&children_graphids);
1284 	DBdelete_graphs(graphids);
1285 
1286 	zbx_vector_uint64_destroy(&children_graphids);
1287 
1288 	zbx_free(sql);
1289 }
1290 
1291 /******************************************************************************
1292  *                                                                            *
1293  * Function: DBdelete_graphs_by_itemids                                       *
1294  *                                                                            *
1295  * Parameters: itemids - [IN] item identificators from database               *
1296  *                                                                            *
1297  * Author: Alexander Vladishev                                                *
1298  *                                                                            *
1299  ******************************************************************************/
DBdelete_graphs_by_itemids(zbx_vector_uint64_t * itemids)1300 static void	DBdelete_graphs_by_itemids(zbx_vector_uint64_t *itemids)
1301 {
1302 	const char		*__function_name = "DBdelete_graphs_by_itemids";
1303 	char			*sql = NULL;
1304 	size_t			sql_alloc = 256, sql_offset;
1305 	DB_RESULT		result;
1306 	DB_ROW			row;
1307 	zbx_uint64_t		graphid;
1308 	zbx_vector_uint64_t	graphids;
1309 	int			index;
1310 
1311 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __function_name, itemids->values_num);
1312 
1313 	if (0 == itemids->values_num)
1314 		goto out;
1315 
1316 	sql = zbx_malloc(sql, sql_alloc);
1317 	zbx_vector_uint64_create(&graphids);
1318 
1319 	/* select all graphs with items */
1320 	sql_offset = 0;
1321 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "select distinct graphid from graphs_items where");
1322 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids->values, itemids->values_num);
1323 
1324 	DBselect_uint64(sql, &graphids);
1325 
1326 	if (0 == graphids.values_num)
1327 		goto clean;
1328 
1329 	/* select graphs with other items */
1330 	sql_offset = 0;
1331 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1332 			"select distinct graphid"
1333 			" from graphs_items"
1334 			" where");
1335 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "graphid", graphids.values, graphids.values_num);
1336 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and not");
1337 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids->values, itemids->values_num);
1338 	result = DBselect("%s", sql);
1339 
1340 	while (NULL != (row = DBfetch(result)))
1341 	{
1342 		ZBX_STR2UINT64(graphid, row[0]);
1343 		if (FAIL != (index = zbx_vector_uint64_bsearch(&graphids, graphid, ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
1344 			zbx_vector_uint64_remove(&graphids, index);
1345 	}
1346 	DBfree_result(result);
1347 
1348 	DBdelete_graph_hierarchy(&graphids);
1349 clean:
1350 	zbx_vector_uint64_destroy(&graphids);
1351 	zbx_free(sql);
1352 out:
1353 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1354 }
1355 
1356 /******************************************************************************
1357  *                                                                            *
1358  * Function: DBdelete_items                                                   *
1359  *                                                                            *
1360  * Purpose: delete items from database                                        *
1361  *                                                                            *
1362  * Parameters: itemids - [IN] array of item identificators from database      *
1363  *                                                                            *
1364  ******************************************************************************/
DBdelete_items(zbx_vector_uint64_t * itemids)1365 void	DBdelete_items(zbx_vector_uint64_t *itemids)
1366 {
1367 	const char		*__function_name = "DBdelete_items";
1368 
1369 	char			*sql = NULL;
1370 	size_t			sql_alloc = 256, sql_offset;
1371 	zbx_vector_uint64_t	screen_itemids, profileids;
1372 	int			num;
1373 	zbx_uint64_t		resource_types[] = {SCREEN_RESOURCE_PLAIN_TEXT, SCREEN_RESOURCE_SIMPLE_GRAPH};
1374 	const char		*profile_idx = "web.favorite.graphids";
1375 
1376 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __function_name, itemids->values_num);
1377 
1378 	if (0 == itemids->values_num)
1379 		goto out;
1380 
1381 	sql = zbx_malloc(sql, sql_alloc);
1382 	zbx_vector_uint64_create(&screen_itemids);
1383 	zbx_vector_uint64_create(&profileids);
1384 
1385 	do	/* add child items (auto-created and prototypes) */
1386 	{
1387 		num = itemids->values_num;
1388 		sql_offset = 0;
1389 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select distinct itemid from item_discovery where");
1390 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "parent_itemid",
1391 				itemids->values, itemids->values_num);
1392 
1393 		DBselect_uint64(sql, itemids);
1394 		zbx_vector_uint64_uniq(itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1395 	}
1396 	while (num != itemids->values_num);
1397 
1398 	DBdelete_graphs_by_itemids(itemids);
1399 	DBdelete_triggers_by_itemids(itemids);
1400 	DBdelete_history_by_itemids(itemids);
1401 
1402 	sql_offset = 0;
1403 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
1404 
1405 	/* delete from screens_items */
1406 	DBget_screenitems_by_resource_types_ids(&screen_itemids, resource_types, ARRSIZE(resource_types), itemids);
1407 	if (0 != screen_itemids.values_num)
1408 	{
1409 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from screens_items where");
1410 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "screenitemid", screen_itemids.values,
1411 				screen_itemids.values_num);
1412 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
1413 	}
1414 
1415 	/* delete from profiles */
1416 	DBget_profiles_by_source_idxs_values(&profileids, "itemid", &profile_idx, 1, itemids);
1417 	if (0 != profileids.values_num)
1418 	{
1419 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from profiles where");
1420 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "profileid", profileids.values,
1421 				profileids.values_num);
1422 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
1423 	}
1424 
1425 	/* delete from items */
1426 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from items where");
1427 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid", itemids->values, itemids->values_num);
1428 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
1429 
1430 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
1431 
1432 	DBexecute("%s", sql);
1433 
1434 	zbx_vector_uint64_destroy(&profileids);
1435 	zbx_vector_uint64_destroy(&screen_itemids);
1436 
1437 	zbx_free(sql);
1438 out:
1439 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1440 }
1441 
1442 /******************************************************************************
1443  *                                                                            *
1444  * Function: DBdelete_httptests                                               *
1445  *                                                                            *
1446  * Purpose: delete web tests from database                                    *
1447  *                                                                            *
1448  * Parameters: httptestids - [IN] array of httptest id's from database        *
1449  *                                                                            *
1450  * Author: Alexander Vladishev                                                *
1451  *                                                                            *
1452  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
1453  *                                                                            *
1454  ******************************************************************************/
DBdelete_httptests(zbx_vector_uint64_t * httptestids)1455 static void	DBdelete_httptests(zbx_vector_uint64_t *httptestids)
1456 {
1457 	const char		*__function_name = "DBdelete_httptests";
1458 
1459 	char			*sql = NULL;
1460 	size_t			sql_alloc = 256, sql_offset = 0;
1461 	zbx_vector_uint64_t	itemids;
1462 
1463 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __function_name, httptestids->values_num);
1464 
1465 	if (0 == httptestids->values_num)
1466 		goto out;
1467 
1468 	sql = zbx_malloc(sql, sql_alloc);
1469 	zbx_vector_uint64_create(&itemids);
1470 
1471 	/* httpstepitem, httptestitem */
1472 	sql_offset = 0;
1473 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
1474 			"select hsi.itemid"
1475 			" from httpstepitem hsi,httpstep hs"
1476 			" where hsi.httpstepid=hs.httpstepid"
1477 				" and");
1478 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hs.httptestid",
1479 			httptestids->values, httptestids->values_num);
1480 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
1481 			" union all "
1482 			"select itemid"
1483 			" from httptestitem"
1484 			" where");
1485 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid",
1486 			httptestids->values, httptestids->values_num);
1487 
1488 	DBselect_uint64(sql, &itemids);
1489 
1490 	DBdelete_items(&itemids);
1491 
1492 	sql_offset = 0;
1493 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from httptest where");
1494 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid",
1495 			httptestids->values, httptestids->values_num);
1496 	DBexecute("%s", sql);
1497 
1498 	zbx_vector_uint64_destroy(&itemids);
1499 	zbx_free(sql);
1500 out:
1501 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1502 }
1503 
1504 /******************************************************************************
1505  *                                                                            *
1506  * Function: DBdelete_application                                             *
1507  *                                                                            *
1508  * Purpose: delete application                                                *
1509  *                                                                            *
1510  * Parameters: applicationid - [IN] application identificator from database   *
1511  *                                                                            *
1512  * Author: Eugene Grigorjev, Alexander Vladishev                              *
1513  *                                                                            *
1514  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
1515  *                                                                            *
1516  ******************************************************************************/
DBdelete_applications(zbx_vector_uint64_t * applicationids)1517 static void	DBdelete_applications(zbx_vector_uint64_t *applicationids)
1518 {
1519 	DB_RESULT	result;
1520 	DB_ROW		row;
1521 	char		*sql = NULL;
1522 	size_t		sql_alloc = 0, sql_offset = 0;
1523 	zbx_uint64_t	applicationid;
1524 	int		index;
1525 
1526 	if (0 == applicationids->values_num)
1527 		goto out;
1528 
1529 	/* don't delete applications used in web scenarios */
1530 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
1531 			"select distinct applicationid"
1532 			" from httptest"
1533 			" where");
1534 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "applicationid", applicationids->values,
1535 			applicationids->values_num);
1536 
1537 	result = DBselect("%s", sql);
1538 
1539 	while (NULL != (row = DBfetch(result)))
1540 	{
1541 		ZBX_STR2UINT64(applicationid, row[0]);
1542 
1543 		index = zbx_vector_uint64_bsearch(applicationids, applicationid, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1544 		zbx_vector_uint64_remove(applicationids, index);
1545 	}
1546 	DBfree_result(result);
1547 
1548 	if (0 == applicationids->values_num)
1549 		goto out;
1550 
1551 	/* don't delete applications with items assigned to them */
1552 	sql_offset = 0;
1553 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
1554 			"select distinct applicationid"
1555 			" from items_applications"
1556 			" where");
1557 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "applicationid", applicationids->values,
1558 			applicationids->values_num);
1559 
1560 	result = DBselect("%s", sql);
1561 
1562 	while (NULL != (row = DBfetch(result)))
1563 	{
1564 		ZBX_STR2UINT64(applicationid, row[0]);
1565 
1566 		index = zbx_vector_uint64_bsearch(applicationids, applicationid, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1567 		zbx_vector_uint64_remove(applicationids, index);
1568 	}
1569 	DBfree_result(result);
1570 
1571 	if (0 == applicationids->values_num)
1572 		goto out;
1573 
1574 	sql_offset = 0;
1575 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
1576 
1577 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from applications where");
1578 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset,
1579 			"applicationid", applicationids->values, applicationids->values_num);
1580 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
1581 
1582 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
1583 
1584 	DBexecute("%s", sql);
1585 out:
1586 	zbx_free(sql);
1587 }
1588 
1589 /******************************************************************************
1590  *                                                                            *
1591  * Function: DBgroup_prototypes_delete                                        *
1592  *                                                                            *
1593  * Parameters: del_group_prototypeids - [IN] list of group_prototypeids which *
1594  *                                      will be deleted                       *
1595  *                                                                            *
1596  ******************************************************************************/
DBgroup_prototypes_delete(zbx_vector_uint64_t * del_group_prototypeids)1597 static void	DBgroup_prototypes_delete(zbx_vector_uint64_t *del_group_prototypeids)
1598 {
1599 	char			*sql = NULL;
1600 	size_t			sql_alloc = 0, sql_offset;
1601 	zbx_vector_uint64_t	groupids;
1602 
1603 	if (0 == del_group_prototypeids->values_num)
1604 		return;
1605 
1606 	zbx_vector_uint64_create(&groupids);
1607 
1608 	sql_offset = 0;
1609 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select groupid from group_discovery where");
1610 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "parent_group_prototypeid",
1611 			del_group_prototypeids->values, del_group_prototypeids->values_num);
1612 
1613 	DBselect_uint64(sql, &groupids);
1614 
1615 	DBdelete_groups(&groupids);
1616 
1617 	sql_offset = 0;
1618 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from group_prototype where");
1619 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "group_prototypeid",
1620 			del_group_prototypeids->values, del_group_prototypeids->values_num);
1621 
1622 	DBexecute("%s", sql);
1623 
1624 	zbx_vector_uint64_destroy(&groupids);
1625 	zbx_free(sql);
1626 }
1627 
1628 /******************************************************************************
1629  *                                                                            *
1630  * Function: DBdelete_host_prototypes                                         *
1631  *                                                                            *
1632  * Purpose: deletes host prototypes from database                             *
1633  *                                                                            *
1634  * Parameters: host_prototypeids - [IN] list of host prototypes               *
1635  *                                                                            *
1636  ******************************************************************************/
DBdelete_host_prototypes(zbx_vector_uint64_t * host_prototypeids)1637 static void	DBdelete_host_prototypes(zbx_vector_uint64_t *host_prototypeids)
1638 {
1639 	char			*sql = NULL;
1640 	size_t			sql_alloc = 0, sql_offset;
1641 	zbx_vector_uint64_t	hostids, group_prototypeids;
1642 
1643 	if (0 == host_prototypeids->values_num)
1644 		return;
1645 
1646 	/* delete discovered hosts */
1647 
1648 	zbx_vector_uint64_create(&hostids);
1649 	zbx_vector_uint64_create(&group_prototypeids);
1650 
1651 	sql_offset = 0;
1652 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select hostid from host_discovery where");
1653 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "parent_hostid",
1654 			host_prototypeids->values, host_prototypeids->values_num);
1655 
1656 	DBselect_uint64(sql, &hostids);
1657 
1658 	if (0 != hostids.values_num)
1659 		DBdelete_hosts(&hostids);
1660 
1661 	/* delete group prototypes */
1662 
1663 	sql_offset = 0;
1664 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select group_prototypeid from group_prototype where");
1665 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
1666 			host_prototypeids->values, host_prototypeids->values_num);
1667 
1668 	DBselect_uint64(sql, &group_prototypeids);
1669 
1670 	DBgroup_prototypes_delete(&group_prototypeids);
1671 
1672 	/* delete host prototypes */
1673 
1674 	sql_offset = 0;
1675 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from hosts where");
1676 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
1677 			host_prototypeids->values, host_prototypeids->values_num);
1678 
1679 	DBexecute("%s", sql);
1680 
1681 	zbx_vector_uint64_destroy(&group_prototypeids);
1682 	zbx_vector_uint64_destroy(&hostids);
1683 	zbx_free(sql);
1684 }
1685 
1686 /******************************************************************************
1687  *                                                                            *
1688  * Function: DBdelete_template_httptests                                      *
1689  *                                                                            *
1690  * Purpose: delete template web scenatios from host                           *
1691  *                                                                            *
1692  * Parameters: hostid      - [IN] host identificator from database            *
1693  *             templateids - [IN] array of template IDs                       *
1694  *                                                                            *
1695  ******************************************************************************/
DBdelete_template_httptests(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)1696 static void	DBdelete_template_httptests(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
1697 {
1698 	const char		*__function_name = "DBdelete_template_httptests";
1699 
1700 	char			*sql = NULL;
1701 	size_t			sql_alloc = 0, sql_offset = 0;
1702 	zbx_vector_uint64_t	httptestids;
1703 
1704 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1705 
1706 	zbx_vector_uint64_create(&httptestids);
1707 
1708 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1709 			"select h.httptestid"
1710 			" from httptest h"
1711 				" join httptest t"
1712 					" on");
1713 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.hostid", templateids->values, templateids->values_num);
1714 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1715 						" and t.httptestid=h.templateid"
1716 			" where h.hostid=" ZBX_FS_UI64, hostid);
1717 
1718 	DBselect_uint64(sql, &httptestids);
1719 
1720 	DBdelete_httptests(&httptestids);
1721 
1722 	zbx_vector_uint64_destroy(&httptestids);
1723 	zbx_free(sql);
1724 
1725 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1726 }
1727 
1728 /******************************************************************************
1729  *                                                                            *
1730  * Function: DBdelete_template_graphs                                         *
1731  *                                                                            *
1732  * Purpose: delete template graphs from host                                  *
1733  *                                                                            *
1734  * Parameters: hostid      - [IN] host identificator from database            *
1735  *             templateids - [IN] array of template IDs                       *
1736  *                                                                            *
1737  * Author: Eugene Grigorjev                                                   *
1738  *                                                                            *
1739  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
1740  *                                                                            *
1741  ******************************************************************************/
DBdelete_template_graphs(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)1742 static void	DBdelete_template_graphs(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
1743 {
1744 	const char		*__function_name = "DBdelete_template_graphs";
1745 
1746 	char			*sql = NULL;
1747 	size_t			sql_alloc = 0, sql_offset = 0;
1748 	zbx_vector_uint64_t	graphids;
1749 
1750 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1751 
1752 	zbx_vector_uint64_create(&graphids);
1753 
1754 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1755 			"select distinct gi.graphid"
1756 			" from graphs_items gi,items i,items ti"
1757 			" where gi.itemid=i.itemid"
1758 				" and i.templateid=ti.itemid"
1759 				" and i.hostid=" ZBX_FS_UI64
1760 				" and",
1761 			hostid);
1762 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", templateids->values, templateids->values_num);
1763 
1764 	DBselect_uint64(sql, &graphids);
1765 
1766 	DBdelete_graph_hierarchy(&graphids);
1767 
1768 	zbx_vector_uint64_destroy(&graphids);
1769 	zbx_free(sql);
1770 
1771 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1772 }
1773 
1774 /******************************************************************************
1775  *                                                                            *
1776  * Function: DBdelete_template_triggers                                       *
1777  *                                                                            *
1778  * Purpose: delete template triggers from host                                *
1779  *                                                                            *
1780  * Parameters: hostid      - [IN] host identificator from database            *
1781  *             templateids - [IN] array of template IDs                       *
1782  *                                                                            *
1783  * Author: Eugene Grigorjev                                                   *
1784  *                                                                            *
1785  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
1786  *                                                                            *
1787  ******************************************************************************/
DBdelete_template_triggers(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)1788 static void	DBdelete_template_triggers(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
1789 {
1790 	const char		*__function_name = "DBdelete_template_triggers";
1791 
1792 	char			*sql = NULL;
1793 	size_t			sql_alloc = 0, sql_offset = 0;
1794 	zbx_vector_uint64_t	triggerids;
1795 
1796 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1797 
1798 	zbx_vector_uint64_create(&triggerids);
1799 
1800 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1801 			"select distinct f.triggerid"
1802 			" from functions f,items i,items ti"
1803 			" where f.itemid=i.itemid"
1804 				" and i.templateid=ti.itemid"
1805 				" and i.hostid=" ZBX_FS_UI64
1806 				" and",
1807 			hostid);
1808 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", templateids->values, templateids->values_num);
1809 
1810 	DBselect_uint64(sql, &triggerids);
1811 
1812 	DBdelete_trigger_hierarchy(&triggerids);
1813 
1814 	zbx_vector_uint64_destroy(&triggerids);
1815 	zbx_free(sql);
1816 
1817 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1818 }
1819 
1820 /******************************************************************************
1821  *                                                                            *
1822  * Function: DBdelete_template_host_prototypes                                *
1823  *                                                                            *
1824  * Purpose: delete template host prototypes from host                         *
1825  *                                                                            *
1826  * Parameters: hostid      - [IN] host identificator from database            *
1827  *             templateids - [IN] array of template IDs                       *
1828  *                                                                            *
1829  ******************************************************************************/
DBdelete_template_host_prototypes(zbx_uint64_t hostid,zbx_vector_uint64_t * templateids)1830 static void	DBdelete_template_host_prototypes(zbx_uint64_t hostid, zbx_vector_uint64_t *templateids)
1831 {
1832 	const char		*__function_name = "DBdelete_template_host_prototypes";
1833 
1834 	char			*sql = NULL;
1835 	size_t			sql_alloc = 0, sql_offset = 0;
1836 	zbx_vector_uint64_t	host_prototypeids;
1837 
1838 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1839 
1840 	zbx_vector_uint64_create(&host_prototypeids);
1841 
1842 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1843 			"select hp.hostid"
1844 			" from items hi,host_discovery hhd,hosts hp,host_discovery thd,items ti"
1845 			" where hi.itemid=hhd.parent_itemid"
1846 				" and hhd.hostid=hp.hostid"
1847 				" and hp.templateid=thd.hostid"
1848 				" and thd.parent_itemid=ti.itemid"
1849 				" and hi.hostid=" ZBX_FS_UI64
1850 				" and",
1851 			hostid);
1852 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", templateids->values, templateids->values_num);
1853 
1854 	DBselect_uint64(sql, &host_prototypeids);
1855 
1856 	DBdelete_host_prototypes(&host_prototypeids);
1857 
1858 	zbx_free(sql);
1859 
1860 	zbx_vector_uint64_destroy(&host_prototypeids);
1861 
1862 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1863 }
1864 
1865 /******************************************************************************
1866  *                                                                            *
1867  * Function: DBdelete_template_items                                          *
1868  *                                                                            *
1869  * Purpose: delete template items from host                                   *
1870  *                                                                            *
1871  * Parameters: hostid      - [IN] host identificator from database            *
1872  *             templateids - [IN] array of template IDs                       *
1873  *                                                                            *
1874  * Author: Eugene Grigorjev                                                   *
1875  *                                                                            *
1876  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
1877  *                                                                            *
1878  ******************************************************************************/
DBdelete_template_items(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)1879 static void	DBdelete_template_items(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
1880 {
1881 	const char		*__function_name = "DBdelete_template_items";
1882 
1883 	char			*sql = NULL;
1884 	size_t			sql_alloc = 0, sql_offset = 0;
1885 	zbx_vector_uint64_t	itemids;
1886 
1887 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1888 
1889 	zbx_vector_uint64_create(&itemids);
1890 
1891 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1892 			"select distinct i.itemid"
1893 			" from items i,items ti"
1894 			" where i.templateid=ti.itemid"
1895 				" and i.hostid=" ZBX_FS_UI64
1896 				" and",
1897 			hostid);
1898 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", templateids->values, templateids->values_num);
1899 
1900 	DBselect_uint64(sql, &itemids);
1901 
1902 	DBdelete_items(&itemids);
1903 
1904 	zbx_vector_uint64_destroy(&itemids);
1905 	zbx_free(sql);
1906 
1907 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1908 }
1909 
1910 /******************************************************************************
1911  *                                                                            *
1912  * Function: DBdelete_template_applications                                   *
1913  *                                                                            *
1914  * Purpose: delete host applications that belong to an unlinked template      *
1915  *                                                                            *
1916  * Parameters: hostid      - [IN] host identificator from database            *
1917  *             templateids - [IN] array of template IDs                       *
1918  *                                                                            *
1919  * Author: Eugene Grigorjev                                                   *
1920  *                                                                            *
1921  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
1922  *                                                                            *
1923  *           This function does not remove applications discovered by         *
1924  *           application prototypes.                                          *
1925  *           Use DBdelete_template_discovered_applications() for that.        *
1926  *                                                                            *
1927  ******************************************************************************/
DBdelete_template_applications(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)1928 static void	DBdelete_template_applications(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
1929 {
1930 	const char		*__function_name = "DBdelete_template_applications";
1931 
1932 	DB_RESULT		result;
1933 	DB_ROW			row;
1934 	char			*sql = NULL;
1935 	size_t			sql_alloc = 0, sql_offset = 0;
1936 	zbx_uint64_t		id;
1937 	zbx_vector_uint64_t	applicationids, apptemplateids;
1938 
1939 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1940 
1941 	zbx_vector_uint64_create(&applicationids);
1942 	zbx_vector_uint64_create(&apptemplateids);
1943 
1944 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1945 			"select t.application_templateid,t.applicationid"
1946 			" from application_template t,applications a,applications ta"
1947 			" where t.applicationid=a.applicationid"
1948 				" and t.templateid=ta.applicationid"
1949 				" and a.hostid=" ZBX_FS_UI64
1950 				" and a.flags=%d"
1951 				" and",
1952 			hostid, ZBX_FLAG_DISCOVERY_NORMAL);
1953 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ta.hostid", templateids->values, templateids->values_num);
1954 
1955 	result = DBselect("%s", sql);
1956 
1957 	while (NULL != (row = DBfetch(result)))
1958 	{
1959 		ZBX_STR2UINT64(id, row[0]);
1960 		zbx_vector_uint64_append(&apptemplateids, id);
1961 
1962 		ZBX_STR2UINT64(id, row[1]);
1963 		zbx_vector_uint64_append(&applicationids, id);
1964 	}
1965 	DBfree_result(result);
1966 
1967 	if (0 != apptemplateids.values_num)
1968 	{
1969 		zbx_vector_uint64_sort(&apptemplateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1970 
1971 		zbx_vector_uint64_sort(&applicationids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1972 		zbx_vector_uint64_uniq(&applicationids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1973 
1974 		sql_offset = 0;
1975 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from application_template where");
1976 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "application_templateid",
1977 				apptemplateids.values, apptemplateids.values_num);
1978 
1979 		DBexecute("%s", sql);
1980 
1981 		DBdelete_applications(&applicationids);
1982 	}
1983 
1984 	zbx_vector_uint64_destroy(&apptemplateids);
1985 	zbx_vector_uint64_destroy(&applicationids);
1986 	zbx_free(sql);
1987 
1988 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1989 }
1990 
1991 /******************************************************************************
1992  *                                                                            *
1993  * Function: DBdelete_template_discovered_applications                        *
1994  *                                                                            *
1995  * Purpose: delete host applications that belong to an unlinked template      *
1996  *                                                                            *
1997  * Parameters: hostid      - [IN] host identificator from database            *
1998  *             templateids - [IN] array of template IDs                       *
1999  *                                                                            *
2000  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
2001  *                                                                            *
2002  ******************************************************************************/
DBdelete_template_discovered_applications(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)2003 static void	DBdelete_template_discovered_applications(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
2004 {
2005 	const char		*__function_name = "DBdelete_template_discovered_applications";
2006 
2007 	DB_RESULT		result;
2008 	DB_ROW			row;
2009 	char			*sql = NULL;
2010 	size_t			sql_alloc = 0, sql_offset = 0;
2011 	zbx_uint64_t		id;
2012 	zbx_vector_uint64_t	applicationids, lld_ruleids;
2013 	int			index;
2014 
2015 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2016 
2017 	zbx_vector_uint64_create(&applicationids);
2018 	zbx_vector_uint64_create(&lld_ruleids);
2019 
2020 	/* get the discovery rules */
2021 
2022 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2023 			"select i.itemid from items i"
2024 			" left join items ti"
2025 				" on i.templateid=ti.itemid"
2026 			" where i.hostid=" ZBX_FS_UI64
2027 				" and i.flags=%d"
2028 				" and",
2029 			hostid, ZBX_FLAG_DISCOVERY_RULE);
2030 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", templateids->values, templateids->values_num);
2031 
2032 	DBselect_uint64(sql, &lld_ruleids);
2033 
2034 	if (0 == lld_ruleids.values_num)
2035 		goto out;
2036 
2037 	/* get the applications discovered by those rules */
2038 
2039 	sql_offset = 0;
2040 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2041 			"select ad.applicationid"
2042 			" from application_discovery ad"
2043 			" left join application_prototype ap"
2044 				" on ap.application_prototypeid=ad.application_prototypeid"
2045 			" where");
2046 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ap.itemid", lld_ruleids.values, lld_ruleids.values_num);
2047 
2048 	zbx_vector_uint64_clear(&applicationids);
2049 	DBselect_uint64(sql, &applicationids);
2050 
2051 	if (0 == applicationids.values_num)
2052 		goto out;
2053 
2054 	/* check if the applications are not discovered by other discovery rules */
2055 
2056 	sql_offset = 0;
2057 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
2058 			"select ad.applicationid"
2059 			" from application_discovery ad"
2060 			" left join application_prototype ap"
2061 				" on ad.application_prototypeid=ap.application_prototypeid"
2062 			" where not");
2063 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ap.itemid", lld_ruleids.values, lld_ruleids.values_num);
2064 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and");
2065 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ad.applicationid", applicationids.values,
2066 			applicationids.values_num);
2067 
2068 	result = DBselect("%s", sql);
2069 
2070 	while (NULL != (row = DBfetch(result)))
2071 	{
2072 		ZBX_STR2UINT64(id, row[0]);
2073 
2074 		if (FAIL != (index = zbx_vector_uint64_bsearch(&applicationids, id, ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
2075 			zbx_vector_uint64_remove(&applicationids, index);
2076 	}
2077 	DBfree_result(result);
2078 
2079 	if (0 == applicationids.values_num)
2080 		goto out;
2081 
2082 	/* discovered applications must be always removed, that's why we are  */
2083 	/* doing it directly instead of using DBdelete_applications()         */
2084 	sql_offset = 0;
2085 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from applications where");
2086 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "applicationid", applicationids.values
2087 			, applicationids.values_num);
2088 	DBexecute("%s", sql);
2089 out:
2090 	zbx_vector_uint64_destroy(&lld_ruleids);
2091 	zbx_vector_uint64_destroy(&applicationids);
2092 	zbx_free(sql);
2093 
2094 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2095 }
2096 
2097 /******************************************************************************
2098  *                                                                            *
2099  * Function: DBcopy_trigger_to_host                                           *
2100  *                                                                            *
2101  * Purpose: copy specified trigger to host                                    *
2102  *                                                                            *
2103  * Parameters: hostid - host identificator from database                      *
2104  *             triggerid - trigger identificator from database                *
2105  *             description - trigger description                              *
2106  *             expression - trigger expression                                *
2107  *             status - trigger status                                        *
2108  *             type - trigger type                                            *
2109  *             priority - trigger priority                                    *
2110  *             comments - trigger comments                                    *
2111  *             url - trigger url                                              *
2112  *                                                                            *
2113  * Return value: upon successful completion return SUCCEED                    *
2114  *                                                                            *
2115  * Author: Eugene Grigorjev, Alexander Vladishev                              *
2116  *                                                                            *
2117  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
2118  *                                                                            *
2119  ******************************************************************************/
DBcopy_trigger_to_host(zbx_uint64_t * new_triggerid,zbx_uint64_t hostid,zbx_uint64_t triggerid,const char * description,const char * expression,unsigned char status,unsigned char type,unsigned char priority,const char * comments,const char * url,unsigned char flags)2120 static int	DBcopy_trigger_to_host(zbx_uint64_t *new_triggerid, zbx_uint64_t hostid,
2121 		zbx_uint64_t triggerid, const char *description, const char *expression,
2122 		unsigned char status, unsigned char type, unsigned char priority,
2123 		const char *comments, const char *url, unsigned char flags)
2124 {
2125 	DB_RESULT	result;
2126 	DB_ROW		row;
2127 	char		*sql = NULL;
2128 	size_t		sql_alloc = 256, sql_offset = 0;
2129 	zbx_uint64_t	itemid,	h_triggerid, functionid;
2130 	char		*old_expression = NULL,
2131 			*new_expression = NULL,
2132 			*expression_esc = NULL,
2133 			*search = NULL,
2134 			*replace = NULL,
2135 			*description_esc = NULL,
2136 			*comments_esc = NULL,
2137 			*url_esc = NULL,
2138 			*function_esc = NULL,
2139 			*parameter_esc = NULL;
2140 	int		res = FAIL;
2141 
2142 	sql = zbx_malloc(sql, sql_alloc);
2143 
2144 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
2145 
2146 	description_esc = DBdyn_escape_string(description);
2147 
2148 	result = DBselect(
2149 			"select distinct t.triggerid,t.expression"
2150 			" from triggers t,functions f,items i"
2151 			" where t.triggerid=f.triggerid"
2152 				" and f.itemid=i.itemid"
2153 				" and t.templateid is null"
2154 				" and i.hostid=" ZBX_FS_UI64
2155 				" and t.description='%s'",
2156 			hostid, description_esc);
2157 
2158 	while (NULL != (row = DBfetch(result)))
2159 	{
2160 		ZBX_STR2UINT64(h_triggerid, row[0]);
2161 
2162 		if (SUCCEED != DBcmp_triggers(triggerid, expression,
2163 				h_triggerid, row[1]))
2164 			continue;
2165 
2166 		/* link not linked trigger with same description and expression */
2167 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2168 				"update triggers"
2169 				" set templateid=" ZBX_FS_UI64 ","
2170 					"flags=%d"
2171 				" where triggerid=" ZBX_FS_UI64 ";\n",
2172 				triggerid, (int)flags, h_triggerid);
2173 
2174 		res = SUCCEED;
2175 		break;
2176 	}
2177 	DBfree_result(result);
2178 
2179 	/* create trigger if no updated triggers */
2180 	if (SUCCEED != res)
2181 	{
2182 		res = SUCCEED;
2183 
2184 		*new_triggerid = DBget_maxid("triggers");
2185 		new_expression = strdup(expression);
2186 
2187 		comments_esc = DBdyn_escape_string(comments);
2188 		url_esc = DBdyn_escape_string(url);
2189 
2190 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2191 				"insert into triggers"
2192 					" (triggerid,description,priority,status,"
2193 						"comments,url,type,value,state,templateid,flags)"
2194 					" values (" ZBX_FS_UI64 ",'%s',%d,%d,"
2195 						"'%s','%s',%d,%d,%d," ZBX_FS_UI64 ",%d);\n",
2196 					*new_triggerid, description_esc, (int)priority, (int)status, comments_esc,
2197 					url_esc, (int)type, TRIGGER_VALUE_OK, TRIGGER_STATE_NORMAL, triggerid,
2198 					(int)flags);
2199 
2200 		zbx_free(url_esc);
2201 		zbx_free(comments_esc);
2202 
2203 		/* Loop: functions */
2204 		result = DBselect(
2205 				"select hi.itemid,tf.functionid,tf.function,tf.parameter,ti.key_"
2206 				" from functions tf,items ti"
2207 				" left join items hi"
2208 					" on hi.key_=ti.key_"
2209 						" and hi.hostid=" ZBX_FS_UI64
2210 				" where tf.itemid=ti.itemid"
2211 					" and tf.triggerid=" ZBX_FS_UI64,
2212 				hostid, triggerid);
2213 
2214 		while (SUCCEED == res && NULL != (row = DBfetch(result)))
2215 		{
2216 			if (SUCCEED != DBis_null(row[0]))
2217 			{
2218 				ZBX_STR2UINT64(itemid, row[0]);
2219 
2220 				functionid = DBget_maxid("functions");
2221 
2222 				search = zbx_dsprintf(NULL, "{%s}", row[1]);
2223 				replace = zbx_dsprintf(NULL, "{" ZBX_FS_UI64 "}", functionid);
2224 
2225 				function_esc = DBdyn_escape_string(row[2]);
2226 				parameter_esc = DBdyn_escape_string(row[3]);
2227 
2228 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2229 						"insert into functions"
2230 						" (functionid,itemid,triggerid,function,parameter)"
2231 						" values (" ZBX_FS_UI64 "," ZBX_FS_UI64 ","
2232 							ZBX_FS_UI64 ",'%s','%s');\n",
2233 						functionid, itemid, *new_triggerid,
2234 						function_esc, parameter_esc);
2235 
2236 				old_expression = new_expression;
2237 				new_expression = string_replace(old_expression, search, replace);
2238 
2239 				zbx_free(old_expression);
2240 				zbx_free(parameter_esc);
2241 				zbx_free(function_esc);
2242 				zbx_free(replace);
2243 				zbx_free(search);
2244 			}
2245 			else
2246 			{
2247 				zabbix_log(LOG_LEVEL_DEBUG, "Missing similar key '%s'"
2248 						" for host [" ZBX_FS_UI64 "]",
2249 						row[4], hostid);
2250 				res = FAIL;
2251 			}
2252 		}
2253 		DBfree_result(result);
2254 
2255 		if (SUCCEED == res)
2256 		{
2257 			expression_esc = DBdyn_escape_field("triggers", "expression", new_expression);
2258 
2259 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2260 					"update triggers set expression='%s' where triggerid=" ZBX_FS_UI64 ";\n",
2261 					expression_esc, *new_triggerid);
2262 
2263 			zbx_free(expression_esc);
2264 		}
2265 
2266 		zbx_free(new_expression);
2267 	}
2268 	else
2269 		*new_triggerid = 0;
2270 
2271 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
2272 
2273 	if (sql_offset > 16)	/* In ORACLE always present begin..end; */
2274 		DBexecute("%s", sql);
2275 
2276 	zbx_free(sql);
2277 	zbx_free(description_esc);
2278 
2279 	return res;
2280 }
2281 
2282 /******************************************************************************
2283  *                                                                            *
2284  * Function: DBresolve_template_trigger_dependencies                          *
2285  *                                                                            *
2286  * Purpose: resolves trigger dependencies for the specified triggers based on *
2287  *          host and linked templates                                         *
2288  *                                                                            *
2289  * Parameters: hostid    - [IN] host identificator from database              *
2290  *             trids     - [IN] array of trigger identifiers from database    *
2291  *             trids_num - [IN] trigger count in trids array                  *
2292  *             links     - [OUT] pairs of trigger dependencies  (down,up)     *
2293  *                                                                            *
2294  ******************************************************************************/
DBresolve_template_trigger_dependencies(zbx_uint64_t hostid,const zbx_uint64_t * trids,int trids_num,zbx_vector_uint64_pair_t * links)2295 static void	DBresolve_template_trigger_dependencies(zbx_uint64_t hostid, const zbx_uint64_t *trids,
2296 		int trids_num, zbx_vector_uint64_pair_t *links)
2297 {
2298 	DB_RESULT			result;
2299 	DB_ROW				row;
2300 	zbx_uint64_pair_t		map_id, dep_list_id;
2301 	char				*sql = NULL;
2302 	size_t				sql_alloc = 512, sql_offset;
2303 	zbx_vector_uint64_pair_t	dep_list_ids, map_ids;
2304 	zbx_vector_uint64_t		all_templ_ids;
2305 	zbx_uint64_t			templateid_down, templateid_up,
2306 					triggerid_down, triggerid_up,
2307 					hst_triggerid, tpl_triggerid;
2308 	int				i, j;
2309 
2310 	zbx_vector_uint64_create(&all_templ_ids);
2311 	zbx_vector_uint64_pair_create(&dep_list_ids);
2312 	zbx_vector_uint64_pair_create(links);
2313 	sql = zbx_malloc(sql, sql_alloc);
2314 
2315 	sql_offset = 0;
2316 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
2317 			"select distinct td.triggerid_down,td.triggerid_up"
2318 			" from triggers t,trigger_depends td"
2319 			" where t.templateid in (td.triggerid_up,td.triggerid_down) and");
2320 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.triggerid", trids, trids_num);
2321 
2322 	result = DBselect("%s", sql);
2323 
2324 	while (NULL != (row = DBfetch(result)))
2325 	{
2326 		ZBX_STR2UINT64(dep_list_id.first, row[0]);
2327 		ZBX_STR2UINT64(dep_list_id.second, row[1]);
2328 		zbx_vector_uint64_pair_append(&dep_list_ids, dep_list_id);
2329 		zbx_vector_uint64_append(&all_templ_ids, dep_list_id.first);
2330 		zbx_vector_uint64_append(&all_templ_ids, dep_list_id.second);
2331 
2332 	}
2333 	DBfree_result(result);
2334 
2335 	if (0 == dep_list_ids.values_num)	/* not all trigger template have a dependency trigger */
2336 	{
2337 		zbx_vector_uint64_destroy(&all_templ_ids);
2338 		zbx_vector_uint64_pair_destroy(&dep_list_ids);
2339 		zbx_free(sql);
2340 		return;
2341 	}
2342 
2343 	zbx_vector_uint64_pair_create(&map_ids);
2344 	zbx_vector_uint64_sort(&all_templ_ids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2345 	zbx_vector_uint64_uniq(&all_templ_ids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2346 
2347 	sql_offset = 0;
2348 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2349 			"select t.triggerid,t.templateid"
2350 			" from triggers t,functions f,items i"
2351 			" where t.triggerid=f.triggerid"
2352 				" and f.itemid=i.itemid"
2353 				" and i.hostid=" ZBX_FS_UI64
2354 				" and",
2355 				hostid);
2356 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.templateid", all_templ_ids.values,
2357 			all_templ_ids.values_num);
2358 
2359 	result = DBselect("%s", sql);
2360 
2361 	while (NULL != (row = DBfetch(result)))
2362 	{
2363 		ZBX_STR2UINT64(map_id.first, row[0]);
2364 		ZBX_DBROW2UINT64(map_id.second, row[1]);
2365 		zbx_vector_uint64_pair_append(&map_ids, map_id);
2366 	}
2367 	DBfree_result(result);
2368 
2369 	zbx_free(sql);
2370 	zbx_vector_uint64_destroy(&all_templ_ids);
2371 
2372 	for (i = 0; i < dep_list_ids.values_num; i++)
2373 	{
2374 		templateid_down = dep_list_ids.values[i].first;
2375 		templateid_up = dep_list_ids.values[i].second;
2376 
2377 		/* Convert template ids to corresponding trigger ids.         */
2378 		/* If template trigger depends on host trigger rather than    */
2379 		/* template trigger then up id conversion will fail and the   */
2380 		/* original value (host trigger id) will be used as intended. */
2381 		triggerid_down = 0;
2382 		triggerid_up = templateid_up;
2383 
2384 		for (j = 0; j < map_ids.values_num; j++)
2385 		{
2386 			hst_triggerid = map_ids.values[j].first;
2387 			tpl_triggerid = map_ids.values[j].second;
2388 
2389 			if (tpl_triggerid == templateid_down)
2390 				triggerid_down = hst_triggerid;
2391 
2392 			if (tpl_triggerid == templateid_up)
2393 				triggerid_up = hst_triggerid;
2394 		}
2395 
2396 		if (0 != triggerid_down)
2397 		{
2398 			zbx_uint64_pair_t	link = {triggerid_down, triggerid_up};
2399 
2400 			zbx_vector_uint64_pair_append(links, link);
2401 		}
2402 	}
2403 
2404 	zbx_vector_uint64_pair_destroy(&map_ids);
2405 	zbx_vector_uint64_pair_destroy(&dep_list_ids);
2406 }
2407 
2408 /******************************************************************************
2409  *                                                                            *
2410  * Function: DBadd_template_dependencies_for_new_triggers                     *
2411  *                                                                            *
2412  * Purpose: update trigger dependencies for specified host                    *
2413  *                                                                            *
2414  * Parameters: hostid    - [IN] host identificator from database              *
2415  *             trids     - [IN] array of trigger identifiers from database    *
2416  *             trids_num - [IN] trigger count in trids array                  *
2417  *                                                                            *
2418  * Return value: upon successful completion return SUCCEED                    *
2419  *                                                                            *
2420  * Author: Eugene Grigorjev                                                   *
2421  *                                                                            *
2422  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
2423  *                                                                            *
2424  ******************************************************************************/
DBadd_template_dependencies_for_new_triggers(zbx_uint64_t hostid,zbx_uint64_t * trids,int trids_num)2425 static int	DBadd_template_dependencies_for_new_triggers(zbx_uint64_t hostid, zbx_uint64_t *trids, int trids_num)
2426 {
2427 	int				i;
2428 	zbx_uint64_t			triggerdepid;
2429 	zbx_db_insert_t			db_insert;
2430 	zbx_vector_uint64_pair_t	links;
2431 
2432 	if (0 == trids_num)
2433 		return SUCCEED;
2434 
2435 	DBresolve_template_trigger_dependencies(hostid, trids, trids_num, &links);
2436 
2437 	if (0 < links.values_num)
2438 	{
2439 		triggerdepid = DBget_maxid_num("trigger_depends", links.values_num);
2440 
2441 		zbx_db_insert_prepare(&db_insert, "trigger_depends", "triggerdepid", "triggerid_down", "triggerid_up",
2442 				NULL);
2443 
2444 		for (i = 0; i < links.values_num; i++)
2445 		{
2446 			zbx_db_insert_add_values(&db_insert, triggerdepid++, links.values[i].first,
2447 					links.values[i].second);
2448 		}
2449 
2450 		zbx_db_insert_execute(&db_insert);
2451 		zbx_db_insert_clean(&db_insert);
2452 	}
2453 
2454 	zbx_vector_uint64_pair_destroy(&links);
2455 
2456 	return SUCCEED;
2457 }
2458 
2459 /******************************************************************************
2460  *                                                                            *
2461  * Function: get_templates_by_hostid                                          *
2462  *                                                                            *
2463  * Description: Retrieve already linked templates for specified host          *
2464  *                                                                            *
2465  * Parameters: hostid      - [IN] host identificator from database            *
2466  *             templateids - [IN] array of template IDs                       *
2467  *                                                                            *
2468  * Author: Alexander Vladishev                                                *
2469  *                                                                            *
2470  ******************************************************************************/
get_templates_by_hostid(zbx_uint64_t hostid,zbx_vector_uint64_t * templateids)2471 static void	get_templates_by_hostid(zbx_uint64_t hostid, zbx_vector_uint64_t *templateids)
2472 {
2473 	DB_RESULT	result;
2474 	DB_ROW		row;
2475 	zbx_uint64_t	templateid;
2476 
2477 	result = DBselect(
2478 			"select templateid"
2479 			" from hosts_templates"
2480 			" where hostid=" ZBX_FS_UI64,
2481 			hostid);
2482 
2483 	while (NULL != (row = DBfetch(result)))
2484 	{
2485 		ZBX_STR2UINT64(templateid, row[0]);
2486 		zbx_vector_uint64_append(templateids, templateid);
2487 	}
2488 	DBfree_result(result);
2489 
2490 	zbx_vector_uint64_sort(templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2491 }
2492 
2493 /******************************************************************************
2494  *                                                                            *
2495  * Function: DBdelete_template_elements                                       *
2496  *                                                                            *
2497  * Purpose: delete template elements from host                                *
2498  *                                                                            *
2499  * Parameters: hostid          - [IN] host identificator from database        *
2500  *             del_templateids - [IN] array of template IDs                   *
2501  *                                                                            *
2502  * Author: Eugene Grigorjev                                                   *
2503  *                                                                            *
2504  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
2505  *                                                                            *
2506  ******************************************************************************/
DBdelete_template_elements(zbx_uint64_t hostid,zbx_vector_uint64_t * del_templateids,char ** error)2507 int	DBdelete_template_elements(zbx_uint64_t hostid, zbx_vector_uint64_t *del_templateids, char **error)
2508 {
2509 	const char		*__function_name = "DBdelete_template_elements";
2510 
2511 	char			*sql = NULL, err[MAX_STRING_LEN];
2512 	size_t			sql_alloc = 128, sql_offset = 0;
2513 	zbx_vector_uint64_t	templateids;
2514 	int			i, index, res = SUCCEED;
2515 
2516 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2517 
2518 	zbx_vector_uint64_create(&templateids);
2519 
2520 	get_templates_by_hostid(hostid, &templateids);
2521 
2522 	for (i = 0; i < del_templateids->values_num; i++)
2523 	{
2524 		if (FAIL == (index = zbx_vector_uint64_bsearch(&templateids, del_templateids->values[i],
2525 				ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
2526 		{
2527 			/* template already unlinked */
2528 			zbx_vector_uint64_remove(del_templateids, i--);
2529 		}
2530 		else
2531 			zbx_vector_uint64_remove(&templateids, index);
2532 	}
2533 
2534 	/* all templates already unlinked */
2535 	if (0 == del_templateids->values_num)
2536 		goto clean;
2537 
2538 	if (SUCCEED != (res = validate_linked_templates(&templateids, err, sizeof(err))))
2539 	{
2540 		*error = zbx_strdup(NULL, err);
2541 		goto clean;
2542 	}
2543 
2544 	DBdelete_template_httptests(hostid, del_templateids);
2545 	DBdelete_template_graphs(hostid, del_templateids);
2546 	DBdelete_template_triggers(hostid, del_templateids);
2547 	DBdelete_template_host_prototypes(hostid, del_templateids);
2548 
2549 	/* Removing items will remove discovery rules and all application discovery records */
2550 	/* related to them. Because of that discovered applications must be removed before  */
2551 	/* removing items.                                                                  */
2552 	DBdelete_template_discovered_applications(hostid, del_templateids);
2553 	DBdelete_template_items(hostid, del_templateids);
2554 
2555 	/* normal applications must be removed after items are removed to cleanup */
2556 	/* unlinked applications                                                  */
2557 	DBdelete_template_applications(hostid, del_templateids);
2558 
2559 	sql = zbx_malloc(sql, sql_alloc);
2560 
2561 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2562 			"delete from hosts_templates"
2563 			" where hostid=" ZBX_FS_UI64
2564 				" and",
2565 			hostid);
2566 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "templateid",
2567 			del_templateids->values, del_templateids->values_num);
2568 	DBexecute("%s", sql);
2569 
2570 	zbx_free(sql);
2571 clean:
2572 	zbx_vector_uint64_destroy(&templateids);
2573 
2574 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res));
2575 
2576 	return res;
2577 }
2578 
2579 typedef struct
2580 {
2581 	zbx_uint64_t		applicationid;
2582 	char			*name;
2583 	zbx_vector_uint64_t	templateids;
2584 }
2585 zbx_application_t;
2586 
zbx_application_clean(zbx_application_t * application)2587 static void	zbx_application_clean(zbx_application_t *application)
2588 {
2589 	zbx_vector_uint64_destroy(&application->templateids);
2590 	zbx_free(application->name);
2591 	zbx_free(application);
2592 }
2593 
2594 /******************************************************************************
2595  *                                                                            *
2596  * Function: DBcopy_template_application_prototypes                           *
2597  *                                                                            *
2598  * Purpose: copy application prototypes from templates to host                *
2599  *                                                                            *
2600  * Parameters: hostid      - [IN] host id                                     *
2601  *             templateids - [IN] array of template IDs                       *
2602  *                                                                            *
2603  * Comments: The host items must be already copied.                           *
2604  *                                                                            *
2605  ******************************************************************************/
DBcopy_template_application_prototypes(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)2606 static void	DBcopy_template_application_prototypes(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
2607 {
2608 	const char	*__function_name = "DBcopy_template_application_prototypes";
2609 	DB_RESULT	result;
2610 	DB_ROW		row;
2611 	char		*sql = NULL;
2612 	size_t		sql_alloc = 0, sql_offset = 0;
2613 	zbx_db_insert_t	db_insert;
2614 
2615 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2616 
2617 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2618 			"select ap.application_prototypeid,ap.name,i_t.itemid"
2619 			" from application_prototype ap"
2620 			" left join items i"
2621 				" on ap.itemid=i.itemid"
2622 			" left join items i_t"
2623 				" on i_t.templateid=i.itemid"
2624 			" where i.flags=%d"
2625 				" and i_t.hostid=" ZBX_FS_UI64
2626 				" and",
2627 			ZBX_FLAG_DISCOVERY_RULE, hostid);
2628 
2629 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.hostid", templateids->values, templateids->values_num);
2630 
2631 	result = DBselect("%s", sql);
2632 
2633 	zbx_free(sql);
2634 
2635 	if (NULL == (row = DBfetch(result)))
2636 		goto out;
2637 
2638 	zbx_db_insert_prepare(&db_insert, "application_prototype", "application_prototypeid", "itemid", "templateid",
2639 			"name", NULL);
2640 	do
2641 	{
2642 		zbx_uint64_t	application_prototypeid, lld_ruleid;
2643 
2644 		ZBX_STR2UINT64(application_prototypeid, row[0]);
2645 		ZBX_STR2UINT64(lld_ruleid, row[2]);
2646 
2647 		zbx_db_insert_add_values(&db_insert, __UINT64_C(0), lld_ruleid, application_prototypeid, row[1]);
2648 	}
2649 	while (NULL != (row = DBfetch(result)));
2650 
2651 	zbx_db_insert_autoincrement(&db_insert, "application_prototypeid");
2652 	zbx_db_insert_execute(&db_insert);
2653 	zbx_db_insert_clean(&db_insert);
2654 out:
2655 	DBfree_result(result);
2656 
2657 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2658 }
2659 
2660 /******************************************************************************
2661  *                                                                            *
2662  * Function: DBcopy_template_item_application_prototypes                      *
2663  *                                                                            *
2664  * Purpose: copy application prototypes from templates to host                *
2665  *                                                                            *
2666  * Parameters: hostid      - [IN] host id                                     *
2667  *             templateids - [IN] array of template IDs                       *
2668  *                                                                            *
2669  * Comments: The host items and application prototypes must be already copied.*
2670  *                                                                            *
2671  ******************************************************************************/
DBcopy_template_item_application_prototypes(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)2672 static void	DBcopy_template_item_application_prototypes(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
2673 {
2674 	const char	*__function_name = "DBcopy_template_item_application_prototypes";
2675 	DB_RESULT	result;
2676 	DB_ROW		row;
2677 	char		*sql = NULL;
2678 	size_t		sql_alloc = 0, sql_offset = 0;
2679 	zbx_db_insert_t	db_insert;
2680 
2681 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2682 
2683 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2684 			"select ap.application_prototypeid,i.itemid"
2685 			" from items i_ap,item_application_prototype iap"
2686 			" left join application_prototype ap"
2687 				" on ap.templateid=iap.application_prototypeid"
2688 			" left join items i_t"
2689 				" on i_t.itemid=iap.itemid"
2690 			" left join items i"
2691 				" on i.templateid=i_t.itemid"
2692 			" where i.hostid=" ZBX_FS_UI64
2693 				" and i_ap.itemid=ap.itemid"
2694 				" and i_ap.hostid=" ZBX_FS_UI64
2695 				" and",
2696 			hostid, hostid);
2697 
2698 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i_t.hostid", templateids->values,
2699 			templateids->values_num);
2700 
2701 	result = DBselect("%s", sql);
2702 
2703 	zbx_free(sql);
2704 
2705 	if (NULL == (row = DBfetch(result)))
2706 		goto out;
2707 
2708 	zbx_db_insert_prepare(&db_insert, "item_application_prototype", "item_application_prototypeid",
2709 			"application_prototypeid", "itemid", NULL);
2710 
2711 	do
2712 	{
2713 		zbx_uint64_t	application_prototypeid, itemid;
2714 
2715 		ZBX_STR2UINT64(application_prototypeid, row[0]);
2716 		ZBX_STR2UINT64(itemid, row[1]);
2717 
2718 		zbx_db_insert_add_values(&db_insert, __UINT64_C(0), application_prototypeid, itemid);
2719 	}
2720 	while (NULL != (row = DBfetch(result)));
2721 
2722 	zbx_db_insert_autoincrement(&db_insert, "item_application_prototypeid");
2723 	zbx_db_insert_execute(&db_insert);
2724 	zbx_db_insert_clean(&db_insert);
2725 out:
2726 	DBfree_result(result);
2727 
2728 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2729 }
2730 
2731 /******************************************************************************
2732  *                                                                            *
2733  * Function: DBcopy_template_applications                                     *
2734  *                                                                            *
2735  * Purpose: copy applications from templates to host                          *
2736  *                                                                            *
2737  * Parameters: hostid      - [IN] host id                                     *
2738  *             templateids - [IN] array of template IDs                       *
2739  *                                                                            *
2740  ******************************************************************************/
DBcopy_template_applications(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)2741 static void	DBcopy_template_applications(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
2742 {
2743 	const char		*__function_name = "DBcopy_template_applications";
2744 	DB_RESULT		result;
2745 	DB_ROW			row;
2746 	char			*sql = NULL;
2747 	size_t			sql_alloc = ZBX_KIBIBYTE, sql_offset = 0;
2748 	zbx_application_t	*application = NULL;
2749 	zbx_vector_ptr_t	applications;
2750 	int			i, j, new_applications = 0, new_application_templates = 0;
2751 
2752 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2753 
2754 	zbx_vector_ptr_create(&applications);
2755 
2756 	sql = zbx_malloc(sql, sql_alloc);
2757 
2758 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2759 			"select applicationid,hostid,name"
2760 			" from applications"
2761 			" where hostid=" ZBX_FS_UI64
2762 				" or", hostid);
2763 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", templateids->values, templateids->values_num);
2764 
2765 	result = DBselect("%s", sql);
2766 
2767 	while (NULL != (row = DBfetch(result)))
2768 	{
2769 		zbx_uint64_t	db_applicationid, db_hostid;
2770 
2771 		ZBX_STR2UINT64(db_applicationid, row[0]);
2772 		ZBX_STR2UINT64(db_hostid, row[1]);
2773 
2774 		for (i = 0; i < applications.values_num; i++)
2775 		{
2776 			application = (zbx_application_t *)applications.values[i];
2777 
2778 			if (0 == strcmp(application->name, row[2]))
2779 				break;
2780 		}
2781 
2782 		if (i == applications.values_num)
2783 		{
2784 			application = (zbx_application_t *)zbx_malloc(NULL, sizeof(zbx_application_t));
2785 
2786 			application->applicationid = 0;
2787 			application->name = zbx_strdup(NULL, row[2]);
2788 			zbx_vector_uint64_create(&application->templateids);
2789 
2790 			zbx_vector_ptr_append(&applications, application);
2791 		}
2792 
2793 		if (db_hostid == hostid)
2794 			application->applicationid = db_applicationid;
2795 		else
2796 			zbx_vector_uint64_append(&application->templateids, db_applicationid);
2797 	}
2798 	DBfree_result(result);
2799 
2800 	for (i = 0; i < applications.values_num; i++)
2801 	{
2802 		application = (zbx_application_t *)applications.values[i];
2803 
2804 		if (0 == application->applicationid)
2805 			new_applications++;
2806 
2807 		new_application_templates += application->templateids.values_num;
2808 	}
2809 
2810 	if (0 != new_applications)
2811 	{
2812 		zbx_uint64_t	applicationid;
2813 		zbx_db_insert_t	db_insert;
2814 
2815 		applicationid = DBget_maxid_num("applications", new_applications);
2816 
2817 		zbx_db_insert_prepare(&db_insert, "applications", "applicationid", "hostid", "name", NULL);
2818 
2819 		for (i = 0; i < applications.values_num; i++)
2820 		{
2821 			application = (zbx_application_t *)applications.values[i];
2822 
2823 			if (0 != application->applicationid)
2824 				continue;
2825 
2826 			zbx_db_insert_add_values(&db_insert, applicationid, hostid, application->name);
2827 
2828 			application->applicationid = applicationid++;
2829 		}
2830 
2831 		zbx_db_insert_execute(&db_insert);
2832 		zbx_db_insert_clean(&db_insert);
2833 	}
2834 
2835 	if (0 != new_application_templates)
2836 	{
2837 		zbx_uint64_t	application_templateid;
2838 		zbx_db_insert_t	db_insert;
2839 
2840 		application_templateid = DBget_maxid_num("application_template", new_application_templates);
2841 
2842 		zbx_db_insert_prepare(&db_insert,"application_template", "application_templateid", "applicationid",
2843 				"templateid", NULL);
2844 
2845 		for (i = 0; i < applications.values_num; i++)
2846 		{
2847 			application = (zbx_application_t *)applications.values[i];
2848 
2849 			for (j = 0; j < application->templateids.values_num; j++)
2850 			{
2851 				zbx_db_insert_add_values(&db_insert, application_templateid++,
2852 						application->applicationid, application->templateids.values[j]);
2853 			}
2854 		}
2855 
2856 		zbx_db_insert_execute(&db_insert);
2857 		zbx_db_insert_clean(&db_insert);
2858 	}
2859 
2860 	zbx_vector_ptr_clear_ext(&applications, (zbx_clean_func_t)zbx_application_clean);
2861 	zbx_vector_ptr_destroy(&applications);
2862 	zbx_free(sql);
2863 
2864 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2865 }
2866 
2867 typedef struct
2868 {
2869 	zbx_uint64_t	group_prototypeid;
2870 	zbx_uint64_t	groupid;
2871 	zbx_uint64_t	templateid;	/* reference to parent group_prototypeid */
2872 	char		*name;
2873 }
2874 zbx_group_prototype_t;
2875 
DBgroup_prototype_clean(zbx_group_prototype_t * group_prototype)2876 static void	DBgroup_prototype_clean(zbx_group_prototype_t *group_prototype)
2877 {
2878 	zbx_free(group_prototype->name);
2879 	zbx_free(group_prototype);
2880 }
2881 
DBgroup_prototypes_clean(zbx_vector_ptr_t * group_prototypes)2882 static void	DBgroup_prototypes_clean(zbx_vector_ptr_t *group_prototypes)
2883 {
2884 	int	i;
2885 
2886 	for (i = 0; i < group_prototypes->values_num; i++)
2887 		DBgroup_prototype_clean((zbx_group_prototype_t *)group_prototypes->values[i]);
2888 }
2889 
2890 typedef struct
2891 {
2892 	zbx_uint64_t		templateid;		/* link to parent template */
2893 	zbx_uint64_t		hostid;
2894 	zbx_uint64_t		itemid;			/* discovery rule id */
2895 	zbx_vector_uint64_t	lnk_templateids;	/* list of templates which should be linked */
2896 	zbx_vector_ptr_t	group_prototypes;	/* list of group prototypes */
2897 	char			*host;
2898 	char			*name;
2899 	unsigned char		status;
2900 #define ZBX_FLAG_HPLINK_UPDATE_NAME	0x01
2901 #define ZBX_FLAG_HPLINK_UPDATE_STATUS	0x02
2902 	unsigned char		flags;
2903 }
2904 zbx_host_prototype_t;
2905 
DBhost_prototype_clean(zbx_host_prototype_t * host_prototype)2906 static void	DBhost_prototype_clean(zbx_host_prototype_t *host_prototype)
2907 {
2908 	zbx_free(host_prototype->name);
2909 	zbx_free(host_prototype->host);
2910 	DBgroup_prototypes_clean(&host_prototype->group_prototypes);
2911 	zbx_vector_ptr_destroy(&host_prototype->group_prototypes);
2912 	zbx_vector_uint64_destroy(&host_prototype->lnk_templateids);
2913 	zbx_free(host_prototype);
2914 }
2915 
DBhost_prototypes_clean(zbx_vector_ptr_t * host_prototypes)2916 static void	DBhost_prototypes_clean(zbx_vector_ptr_t *host_prototypes)
2917 {
2918 	int	i;
2919 
2920 	for (i = 0; i < host_prototypes->values_num; i++)
2921 		DBhost_prototype_clean((zbx_host_prototype_t *)host_prototypes->values[i]);
2922 }
2923 
2924 /******************************************************************************
2925  *                                                                            *
2926  * Function: DBis_regular_host                                                *
2927  *                                                                            *
2928  * Comments: auxiliary function for DBcopy_template_host_prototypes()         *
2929  *                                                                            *
2930  ******************************************************************************/
DBis_regular_host(zbx_uint64_t hostid)2931 static int	DBis_regular_host(zbx_uint64_t hostid)
2932 {
2933 	DB_RESULT	result;
2934 	DB_ROW		row;
2935 	int		ret = FAIL;
2936 
2937 	result = DBselect("select flags from hosts where hostid=" ZBX_FS_UI64, hostid);
2938 
2939 	if (NULL != (row = DBfetch(result)))
2940 	{
2941 		if (0 == atoi(row[0]))
2942 			ret = SUCCEED;
2943 	}
2944 	DBfree_result(result);
2945 
2946 	return ret;
2947 }
2948 
2949 /******************************************************************************
2950  *                                                                            *
2951  * Function: DBhost_prototypes_make                                           *
2952  *                                                                            *
2953  * Comments: auxiliary function for DBcopy_template_host_prototypes()         *
2954  *                                                                            *
2955  ******************************************************************************/
DBhost_prototypes_make(zbx_uint64_t hostid,zbx_vector_uint64_t * templateids,zbx_vector_ptr_t * host_prototypes)2956 static void	DBhost_prototypes_make(zbx_uint64_t hostid, zbx_vector_uint64_t *templateids,
2957 		zbx_vector_ptr_t *host_prototypes)
2958 {
2959 	DB_RESULT		result;
2960 	DB_ROW			row;
2961 	char			*sql = NULL;
2962 	size_t			sql_alloc = 0, sql_offset = 0;
2963 	zbx_vector_uint64_t	itemids;
2964 	zbx_host_prototype_t	*host_prototype;
2965 
2966 	zbx_vector_uint64_create(&itemids);
2967 
2968 	/* selects host prototypes from templates */
2969 
2970 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2971 			"select hi.itemid,th.hostid,th.host,th.name,th.status"
2972 			" from items hi,items ti,host_discovery thd,hosts th"
2973 			" where hi.templateid=ti.itemid"
2974 				" and ti.itemid=thd.parent_itemid"
2975 				" and thd.hostid=th.hostid"
2976 				" and hi.hostid=" ZBX_FS_UI64
2977 				" and",
2978 			hostid);
2979 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "ti.hostid", templateids->values, templateids->values_num);
2980 
2981 	result = DBselect("%s", sql);
2982 
2983 	while (NULL != (row = DBfetch(result)))
2984 	{
2985 		host_prototype = (zbx_host_prototype_t *)zbx_malloc(NULL, sizeof(zbx_host_prototype_t));
2986 
2987 		host_prototype->hostid = 0;
2988 		ZBX_STR2UINT64(host_prototype->itemid, row[0]);
2989 		ZBX_STR2UINT64(host_prototype->templateid, row[1]);
2990 		zbx_vector_uint64_create(&host_prototype->lnk_templateids);
2991 		zbx_vector_ptr_create(&host_prototype->group_prototypes);
2992 		host_prototype->host = zbx_strdup(NULL, row[2]);
2993 		host_prototype->name = zbx_strdup(NULL, row[3]);
2994 		host_prototype->status = (unsigned char)atoi(row[4]);
2995 		host_prototype->flags = 0;
2996 
2997 		zbx_vector_ptr_append(host_prototypes, host_prototype);
2998 		zbx_vector_uint64_append(&itemids, host_prototype->itemid);
2999 	}
3000 	DBfree_result(result);
3001 
3002 	if (0 != host_prototypes->values_num)
3003 	{
3004 		zbx_uint64_t	itemid;
3005 		unsigned char	status;
3006 		int		i;
3007 
3008 		zbx_vector_uint64_sort(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3009 		zbx_vector_uint64_uniq(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3010 
3011 		/* selects host prototypes from host */
3012 
3013 		sql_offset = 0;
3014 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3015 				"select i.itemid,h.hostid,h.host,h.name,h.status"
3016 				" from items i,host_discovery hd,hosts h"
3017 				" where i.itemid=hd.parent_itemid"
3018 					" and hd.hostid=h.hostid"
3019 					" and i.hostid=" ZBX_FS_UI64
3020 					" and",
3021 				hostid);
3022 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.itemid", itemids.values, itemids.values_num);
3023 
3024 		result = DBselect("%s", sql);
3025 
3026 		while (NULL != (row = DBfetch(result)))
3027 		{
3028 			ZBX_STR2UINT64(itemid, row[0]);
3029 
3030 			for (i = 0; i < host_prototypes->values_num; i++)
3031 			{
3032 				host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i];
3033 
3034 				if (host_prototype->itemid == itemid && 0 == strcmp(host_prototype->host, row[2]))
3035 				{
3036 					ZBX_STR2UINT64(host_prototype->hostid, row[1]);
3037 					if (0 != strcmp(host_prototype->name, row[3]))
3038 						host_prototype->flags |= ZBX_FLAG_HPLINK_UPDATE_NAME;
3039 					if (host_prototype->status != (status = (unsigned char)atoi(row[4])))
3040 						host_prototype->flags |= ZBX_FLAG_HPLINK_UPDATE_STATUS;
3041 					break;
3042 				}
3043 			}
3044 		}
3045 		DBfree_result(result);
3046 	}
3047 
3048 	zbx_free(sql);
3049 
3050 	zbx_vector_uint64_destroy(&itemids);
3051 
3052 	/* sort by templateid */
3053 	zbx_vector_ptr_sort(host_prototypes, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
3054 }
3055 
3056 /******************************************************************************
3057  *                                                                            *
3058  * Function: DBhost_prototypes_templates_make                                 *
3059  *                                                                            *
3060  * Parameters: host_prototypes     - [IN/OUT] list of host prototypes         *
3061  *                                   should be sorted by templateid           *
3062  *             del_hosttemplateids - [OUT] list of hosttemplateids which      *
3063  *                                   should be deleted                        *
3064  *                                                                            *
3065  * Comments: auxiliary function for DBcopy_template_host_prototypes()         *
3066  *                                                                            *
3067  ******************************************************************************/
DBhost_prototypes_templates_make(zbx_vector_ptr_t * host_prototypes,zbx_vector_uint64_t * del_hosttemplateids)3068 static void	DBhost_prototypes_templates_make(zbx_vector_ptr_t *host_prototypes,
3069 		zbx_vector_uint64_t *del_hosttemplateids)
3070 {
3071 	DB_RESULT		result;
3072 	DB_ROW			row;
3073 	char			*sql = NULL;
3074 	size_t			sql_alloc = 0, sql_offset = 0;
3075 	zbx_vector_uint64_t	hostids;
3076 	zbx_uint64_t		hostid, templateid, hosttemplateid;
3077 	zbx_host_prototype_t	*host_prototype;
3078 	int			i;
3079 
3080 	zbx_vector_uint64_create(&hostids);
3081 
3082 	/* select list of templates which should be linked to host prototypes */
3083 
3084 	for (i = 0; i < host_prototypes->values_num; i++)
3085 	{
3086 		host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i];
3087 
3088 		zbx_vector_uint64_append(&hostids, host_prototype->templateid);
3089 	}
3090 
3091 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
3092 			"select hostid,templateid"
3093 			" from hosts_templates"
3094 			" where");
3095 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
3096 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hostid,templateid");
3097 
3098 	result = DBselect("%s", sql);
3099 
3100 	while (NULL != (row = DBfetch(result)))
3101 	{
3102 		ZBX_STR2UINT64(hostid, row[0]);
3103 		ZBX_STR2UINT64(templateid, row[1]);
3104 
3105 		if (FAIL == (i = zbx_vector_ptr_bsearch(host_prototypes, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
3106 		{
3107 			THIS_SHOULD_NEVER_HAPPEN;
3108 			continue;
3109 		}
3110 
3111 		host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i];
3112 
3113 		zbx_vector_uint64_append(&host_prototype->lnk_templateids, templateid);
3114 	}
3115 	DBfree_result(result);
3116 
3117 	/* select list of templates which already linked to host prototypes */
3118 
3119 	zbx_vector_uint64_clear(&hostids);
3120 
3121 	for (i = 0; i < host_prototypes->values_num; i++)
3122 	{
3123 		host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i];
3124 
3125 		if (0 == host_prototype->hostid)
3126 			continue;
3127 
3128 		zbx_vector_uint64_append(&hostids, host_prototype->hostid);
3129 	}
3130 
3131 	if (0 != hostids.values_num)
3132 	{
3133 		zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3134 
3135 		sql_offset = 0;
3136 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
3137 				"select hostid,templateid,hosttemplateid"
3138 				" from hosts_templates"
3139 				" where");
3140 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
3141 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hosttemplateid");
3142 
3143 		result = DBselect("%s", sql);
3144 
3145 		while (NULL != (row = DBfetch(result)))
3146 		{
3147 			ZBX_STR2UINT64(hostid, row[0]);
3148 			ZBX_STR2UINT64(templateid, row[1]);
3149 
3150 			for (i = 0; i < host_prototypes->values_num; i++)
3151 			{
3152 				host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i];
3153 
3154 				if (host_prototype->hostid == hostid)
3155 					break;
3156 			}
3157 
3158 			if (i == host_prototypes->values_num)
3159 			{
3160 				THIS_SHOULD_NEVER_HAPPEN;
3161 				continue;
3162 			}
3163 
3164 			if (FAIL == (i = zbx_vector_uint64_bsearch(&host_prototype->lnk_templateids, templateid,
3165 						ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
3166 			{
3167 				ZBX_STR2UINT64(hosttemplateid, row[2]);
3168 				zbx_vector_uint64_append(del_hosttemplateids, hosttemplateid);
3169 			}
3170 			else
3171 				zbx_vector_uint64_remove(&host_prototype->lnk_templateids, i);
3172 		}
3173 		DBfree_result(result);
3174 	}
3175 
3176 	zbx_vector_uint64_destroy(&hostids);
3177 
3178 	zbx_free(sql);
3179 }
3180 
3181 /******************************************************************************
3182  *                                                                            *
3183  * Function: DBhost_prototypes_groups_make                                    *
3184  *                                                                            *
3185  * Parameters: host_prototypes        - [IN/OUT] list of host prototypes      *
3186  *                                      should be sorted by templateid        *
3187  *             del_group_prototypeids - [OUT] list of group_prototypeid which *
3188  *                                      should be deleted                     *
3189  *                                                                            *
3190  * Comments: auxiliary function for DBcopy_template_host_prototypes()         *
3191  *                                                                            *
3192  ******************************************************************************/
DBhost_prototypes_groups_make(zbx_vector_ptr_t * host_prototypes,zbx_vector_uint64_t * del_group_prototypeids)3193 static void	DBhost_prototypes_groups_make(zbx_vector_ptr_t *host_prototypes,
3194 		zbx_vector_uint64_t *del_group_prototypeids)
3195 {
3196 	DB_RESULT		result;
3197 	DB_ROW			row;
3198 	char			*sql = NULL;
3199 	size_t			sql_alloc = 0, sql_offset = 0;
3200 	zbx_vector_uint64_t	hostids;
3201 	zbx_uint64_t		hostid, groupid, group_prototypeid;
3202 	zbx_host_prototype_t	*host_prototype;
3203 	zbx_group_prototype_t	*group_prototype;
3204 	int			i;
3205 
3206 	zbx_vector_uint64_create(&hostids);
3207 
3208 	/* select list of groups which should be linked to host prototypes */
3209 
3210 	for (i = 0; i < host_prototypes->values_num; i++)
3211 	{
3212 		host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i];
3213 
3214 		zbx_vector_uint64_append(&hostids, host_prototype->templateid);
3215 	}
3216 
3217 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
3218 			"select hostid,name,groupid,group_prototypeid"
3219 			" from group_prototype"
3220 			" where");
3221 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
3222 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hostid");
3223 
3224 	result = DBselect("%s", sql);
3225 
3226 	while (NULL != (row = DBfetch(result)))
3227 	{
3228 		ZBX_STR2UINT64(hostid, row[0]);
3229 
3230 		if (FAIL == (i = zbx_vector_ptr_bsearch(host_prototypes, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
3231 		{
3232 			THIS_SHOULD_NEVER_HAPPEN;
3233 			continue;
3234 		}
3235 
3236 		host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i];
3237 
3238 		group_prototype = (zbx_group_prototype_t *)zbx_malloc(NULL, sizeof(zbx_group_prototype_t));
3239 		group_prototype->group_prototypeid = 0;
3240 		group_prototype->name = zbx_strdup(NULL, row[1]);
3241 		ZBX_DBROW2UINT64(group_prototype->groupid, row[2]);
3242 		ZBX_STR2UINT64(group_prototype->templateid, row[3]);
3243 
3244 		zbx_vector_ptr_append(&host_prototype->group_prototypes, group_prototype);
3245 	}
3246 	DBfree_result(result);
3247 
3248 	/* select list of group prototypes which already linked to host prototypes */
3249 
3250 	zbx_vector_uint64_clear(&hostids);
3251 
3252 	for (i = 0; i < host_prototypes->values_num; i++)
3253 	{
3254 		host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i];
3255 
3256 		if (0 == host_prototype->hostid)
3257 			continue;
3258 
3259 		zbx_vector_uint64_append(&hostids, host_prototype->hostid);
3260 	}
3261 
3262 	if (0 != hostids.values_num)
3263 	{
3264 		zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3265 
3266 		sql_offset = 0;
3267 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
3268 				"select hostid,group_prototypeid,groupid,name from group_prototype where");
3269 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
3270 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by group_prototypeid");
3271 
3272 		result = DBselect("%s", sql);
3273 
3274 		while (NULL != (row = DBfetch(result)))
3275 		{
3276 			ZBX_STR2UINT64(hostid, row[0]);
3277 
3278 			for (i = 0; i < host_prototypes->values_num; i++)
3279 			{
3280 				host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i];
3281 
3282 				if (host_prototype->hostid == hostid)
3283 					break;
3284 			}
3285 
3286 			if (i == host_prototypes->values_num)
3287 			{
3288 				THIS_SHOULD_NEVER_HAPPEN;
3289 				continue;
3290 			}
3291 
3292 			ZBX_STR2UINT64(group_prototypeid, row[1]);
3293 			ZBX_DBROW2UINT64(groupid, row[2]);
3294 
3295 			for (i = 0; i < host_prototype->group_prototypes.values_num; i++)
3296 			{
3297 				group_prototype = (zbx_group_prototype_t *)host_prototype->group_prototypes.values[i];
3298 
3299 				if (0 != group_prototype->group_prototypeid)
3300 					continue;
3301 
3302 				if (group_prototype->groupid == groupid && 0 == strcmp(group_prototype->name, row[3]))
3303 				{
3304 					group_prototype->group_prototypeid = group_prototypeid;
3305 					break;
3306 				}
3307 			}
3308 
3309 			if (i == host_prototype->group_prototypes.values_num)
3310 				zbx_vector_uint64_append(del_group_prototypeids, group_prototypeid);
3311 		}
3312 		DBfree_result(result);
3313 	}
3314 
3315 	zbx_vector_uint64_sort(del_group_prototypeids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3316 
3317 	zbx_vector_uint64_destroy(&hostids);
3318 	zbx_free(sql);
3319 }
3320 
3321 /******************************************************************************
3322  *                                                                            *
3323  * Function: DBhost_prototypes_save                                           *
3324  *                                                                            *
3325  * Comments: auxiliary function for DBcopy_template_host_prototypes()         *
3326  *                                                                            *
3327  ******************************************************************************/
DBhost_prototypes_save(zbx_vector_ptr_t * host_prototypes,zbx_vector_uint64_t * del_hosttemplateids)3328 static void	DBhost_prototypes_save(zbx_vector_ptr_t *host_prototypes, zbx_vector_uint64_t *del_hosttemplateids)
3329 {
3330 	char			*sql1 = NULL, *sql2 = NULL, *name_esc;
3331 	size_t			sql1_alloc = ZBX_KIBIBYTE, sql1_offset = 0,
3332 				sql2_alloc = ZBX_KIBIBYTE, sql2_offset = 0;
3333 	zbx_host_prototype_t	*host_prototype;
3334 	zbx_group_prototype_t	*group_prototype;
3335 	zbx_uint64_t		hostid = 0, hosttemplateid = 0, group_prototypeid = 0;
3336 	int			i, j, new_hosts = 0, new_hosts_templates = 0, new_group_prototypes = 0,
3337 				upd_group_prototypes = 0;
3338 	zbx_db_insert_t		db_insert, db_insert_hdiscovery, db_insert_htemplates, db_insert_gproto;
3339 
3340 	for (i = 0; i < host_prototypes->values_num; i++)
3341 	{
3342 		host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i];
3343 
3344 		if (0 == host_prototype->hostid)
3345 			new_hosts++;
3346 
3347 		new_hosts_templates += host_prototype->lnk_templateids.values_num;
3348 
3349 		for (j = 0; j < host_prototype->group_prototypes.values_num; j++)
3350 		{
3351 			group_prototype = (zbx_group_prototype_t *)host_prototype->group_prototypes.values[j];
3352 
3353 			if (0 == group_prototype->group_prototypeid)
3354 				new_group_prototypes++;
3355 			else
3356 				upd_group_prototypes++;
3357 		}
3358 	}
3359 
3360 	if (0 != new_hosts)
3361 	{
3362 		hostid = DBget_maxid_num("hosts", new_hosts);
3363 
3364 		zbx_db_insert_prepare(&db_insert, "hosts", "hostid", "host", "name", "status", "flags", "templateid",
3365 				NULL);
3366 
3367 		zbx_db_insert_prepare(&db_insert_hdiscovery, "host_discovery", "hostid", "parent_itemid", NULL);
3368 	}
3369 
3370 	if (new_hosts != host_prototypes->values_num || 0 != upd_group_prototypes)
3371 	{
3372 		sql1 = zbx_malloc(sql1, sql1_alloc);
3373 		DBbegin_multiple_update(&sql1, &sql1_alloc, &sql1_offset);
3374 	}
3375 
3376 	if (0 != new_hosts_templates)
3377 	{
3378 		hosttemplateid = DBget_maxid_num("hosts_templates", new_hosts_templates);
3379 
3380 		zbx_db_insert_prepare(&db_insert_htemplates, "hosts_templates",  "hosttemplateid", "hostid",
3381 				"templateid", NULL);
3382 	}
3383 
3384 	if (0 != del_hosttemplateids->values_num)
3385 	{
3386 		sql2 = zbx_malloc(sql2, sql2_alloc);
3387 		zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from hosts_templates where");
3388 		DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hosttemplateid",
3389 				del_hosttemplateids->values, del_hosttemplateids->values_num);
3390 	}
3391 
3392 	if (0 != new_group_prototypes)
3393 	{
3394 		group_prototypeid = DBget_maxid_num("group_prototype", new_group_prototypes);
3395 
3396 		zbx_db_insert_prepare(&db_insert_gproto, "group_prototype", "group_prototypeid", "hostid", "name",
3397 				"groupid", "templateid", NULL);
3398 	}
3399 
3400 	for (i = 0; i < host_prototypes->values_num; i++)
3401 	{
3402 		host_prototype = (zbx_host_prototype_t *)host_prototypes->values[i];
3403 
3404 		if (0 == host_prototype->hostid)
3405 		{
3406 			host_prototype->hostid = hostid++;
3407 
3408 			zbx_db_insert_add_values(&db_insert, host_prototype->hostid, host_prototype->host,
3409 					host_prototype->name, (int)host_prototype->status,
3410 					(int)ZBX_FLAG_DISCOVERY_PROTOTYPE, host_prototype->templateid);
3411 
3412 			zbx_db_insert_add_values(&db_insert_hdiscovery, host_prototype->hostid, host_prototype->itemid);
3413 		}
3414 		else
3415 		{
3416 			zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "update hosts set templateid=" ZBX_FS_UI64,
3417 					host_prototype->templateid);
3418 			if (0 != (host_prototype->flags & ZBX_FLAG_HPLINK_UPDATE_NAME))
3419 			{
3420 				name_esc = DBdyn_escape_string(host_prototype->name);
3421 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, ",name='%s'", name_esc);
3422 				zbx_free(name_esc);
3423 			}
3424 			if (0 != (host_prototype->flags & ZBX_FLAG_HPLINK_UPDATE_STATUS))
3425 			{
3426 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, ",status=%d",
3427 						host_prototype->status);
3428 			}
3429 			zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, " where hostid=" ZBX_FS_UI64 ";\n",
3430 					host_prototype->hostid);
3431 		}
3432 
3433 		for (j = 0; j < host_prototype->lnk_templateids.values_num; j++)
3434 		{
3435 			zbx_db_insert_add_values(&db_insert_htemplates, hosttemplateid++, host_prototype->hostid,
3436 					host_prototype->lnk_templateids.values[j]);
3437 		}
3438 
3439 		for (j = 0; j < host_prototype->group_prototypes.values_num; j++)
3440 		{
3441 			group_prototype = (zbx_group_prototype_t *)host_prototype->group_prototypes.values[j];
3442 
3443 			if (0 == group_prototype->group_prototypeid)
3444 			{
3445 				zbx_db_insert_add_values(&db_insert_gproto, group_prototypeid++, host_prototype->hostid,
3446 						group_prototype->name, group_prototype->groupid,
3447 						group_prototype->templateid);
3448 			}
3449 			else
3450 			{
3451 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
3452 						"update group_prototype"
3453 						" set templateid=" ZBX_FS_UI64
3454 						" where group_prototypeid=" ZBX_FS_UI64 ";\n",
3455 						group_prototype->templateid, group_prototype->group_prototypeid);
3456 			}
3457 		}
3458 	}
3459 
3460 	if (0 != new_hosts)
3461 	{
3462 		zbx_db_insert_execute(&db_insert);
3463 		zbx_db_insert_clean(&db_insert);
3464 
3465 		zbx_db_insert_execute(&db_insert_hdiscovery);
3466 		zbx_db_insert_clean(&db_insert_hdiscovery);
3467 	}
3468 
3469 	if (0 != new_hosts_templates)
3470 	{
3471 		zbx_db_insert_execute(&db_insert_htemplates);
3472 		zbx_db_insert_clean(&db_insert_htemplates);
3473 	}
3474 
3475 	if (0 != new_group_prototypes)
3476 	{
3477 		zbx_db_insert_execute(&db_insert_gproto);
3478 		zbx_db_insert_clean(&db_insert_gproto);
3479 	}
3480 
3481 	if (new_hosts != host_prototypes->values_num || 0 != upd_group_prototypes)
3482 	{
3483 		DBend_multiple_update(&sql1, &sql1_alloc, &sql1_offset);
3484 		DBexecute("%s", sql1);
3485 		zbx_free(sql1);
3486 	}
3487 
3488 	if (0 != del_hosttemplateids->values_num)
3489 	{
3490 		DBexecute("%s", sql2);
3491 		zbx_free(sql2);
3492 	}
3493 }
3494 
3495 /******************************************************************************
3496  *                                                                            *
3497  * Function: DBcopy_template_host_prototypes                                  *
3498  *                                                                            *
3499  * Purpose: copy host prototypes from templates and create links between      *
3500  *          them and discovery rules                                          *
3501  *                                                                            *
3502  * Comments: auxiliary function for DBcopy_template_elements()                *
3503  *                                                                            *
3504  ******************************************************************************/
DBcopy_template_host_prototypes(zbx_uint64_t hostid,zbx_vector_uint64_t * templateids)3505 static void	DBcopy_template_host_prototypes(zbx_uint64_t hostid, zbx_vector_uint64_t *templateids)
3506 {
3507 	zbx_vector_ptr_t	host_prototypes;
3508 
3509 	/* only regular hosts can have host prototypes */
3510 	if (SUCCEED != DBis_regular_host(hostid))
3511 		return;
3512 
3513 	zbx_vector_ptr_create(&host_prototypes);
3514 
3515 	DBhost_prototypes_make(hostid, templateids, &host_prototypes);
3516 
3517 	if (0 != host_prototypes.values_num)
3518 	{
3519 		zbx_vector_uint64_t	del_hosttemplateids, del_group_prototypeids;
3520 
3521 		zbx_vector_uint64_create(&del_hosttemplateids);
3522 		zbx_vector_uint64_create(&del_group_prototypeids);
3523 
3524 		DBhost_prototypes_templates_make(&host_prototypes, &del_hosttemplateids);
3525 		DBhost_prototypes_groups_make(&host_prototypes, &del_group_prototypeids);
3526 		DBhost_prototypes_save(&host_prototypes, &del_hosttemplateids);
3527 		DBgroup_prototypes_delete(&del_group_prototypeids);
3528 
3529 		zbx_vector_uint64_destroy(&del_group_prototypeids);
3530 		zbx_vector_uint64_destroy(&del_hosttemplateids);
3531 	}
3532 
3533 	DBhost_prototypes_clean(&host_prototypes);
3534 	zbx_vector_ptr_destroy(&host_prototypes);
3535 }
3536 
3537 /******************************************************************************
3538  *                                                                            *
3539  * Function: DBcopy_template_triggers                                         *
3540  *                                                                            *
3541  * Purpose: Copy template triggers to host                                    *
3542  *                                                                            *
3543  * Parameters: hostid      - [IN] host identificator from database            *
3544  *             templateids - [IN] array of template IDs                       *
3545  *                                                                            *
3546  * Return value: upon successful completion return SUCCEED                    *
3547  *                                                                            *
3548  * Author: Eugene Grigorjev                                                   *
3549  *                                                                            *
3550  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
3551  *                                                                            *
3552  ******************************************************************************/
DBcopy_template_triggers(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)3553 static int	DBcopy_template_triggers(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
3554 {
3555 	const char	*__function_name = "DBcopy_template_triggers";
3556 	char		*sql = NULL;
3557 	size_t		sql_alloc = 512, sql_offset = 0;
3558 	DB_RESULT	result;
3559 	DB_ROW		row;
3560 	zbx_uint64_t	triggerid, new_triggerid;
3561 	int		res = SUCCEED;
3562 	zbx_uint64_t	*trids = NULL;
3563 	int		trids_alloc = 0, trids_num = 0;
3564 
3565 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
3566 
3567 	sql = zbx_malloc(sql, sql_alloc);
3568 
3569 	sql_offset = 0;
3570 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
3571 			"select distinct t.triggerid,t.description,t.expression,t.status,"
3572 				"t.type,t.priority,t.comments,t.url,t.flags"
3573 			" from triggers t,functions f,items i"
3574 			" where t.triggerid=f.triggerid"
3575 				" and f.itemid=i.itemid"
3576 				" and");
3577 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.hostid", templateids->values, templateids->values_num);
3578 
3579 	result = DBselect("%s", sql);
3580 
3581 	zbx_free(sql);
3582 
3583 	while (SUCCEED == res && NULL != (row = DBfetch(result)))
3584 	{
3585 		ZBX_STR2UINT64(triggerid, row[0]);
3586 
3587 		res = DBcopy_trigger_to_host(&new_triggerid, hostid, triggerid,
3588 				row[1],				/* description */
3589 				row[2],				/* expression */
3590 				(unsigned char)atoi(row[3]),	/* status */
3591 				(unsigned char)atoi(row[4]),	/* type */
3592 				(unsigned char)atoi(row[5]),	/* priority */
3593 				row[6],				/* comments */
3594 				row[7],				/* url */
3595 				(unsigned char)atoi(row[8]));	/* flags */
3596 
3597 		if (0 != new_triggerid)				/* new trigger added */
3598 			uint64_array_add(&trids, &trids_alloc, &trids_num, new_triggerid, 64);
3599 	}
3600 	DBfree_result(result);
3601 
3602 	if (SUCCEED == res)
3603 		res = DBadd_template_dependencies_for_new_triggers(hostid, trids, trids_num);
3604 
3605 	zbx_free(trids);
3606 
3607 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res));
3608 
3609 	return res;
3610 }
3611 
3612 /******************************************************************************
3613  *                                                                            *
3614  * Function: DBget_same_itemid                                                *
3615  *                                                                            *
3616  * Purpose: get same itemid for selected host by itemid from template         *
3617  *                                                                            *
3618  * Parameters: hostid - host identificator from database                      *
3619  *             itemid - item identificator from database (from template)      *
3620  *                                                                            *
3621  * Return value: new item identificator or zero if item not found             *
3622  *                                                                            *
3623  * Author: Alexander Vladishev                                                *
3624  *                                                                            *
3625  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
3626  *                                                                            *
3627  ******************************************************************************/
DBget_same_itemid(zbx_uint64_t hostid,zbx_uint64_t titemid)3628 static zbx_uint64_t	DBget_same_itemid(zbx_uint64_t hostid, zbx_uint64_t titemid)
3629 {
3630 	const char	*__function_name = "DBget_same_itemid";
3631 	DB_RESULT	result;
3632 	DB_ROW		row;
3633 	zbx_uint64_t	itemid = 0;
3634 
3635 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() hostid:" ZBX_FS_UI64
3636 			" titemid:" ZBX_FS_UI64,
3637 			__function_name, hostid, titemid);
3638 
3639 	result = DBselect(
3640 			"select hi.itemid"
3641 			" from items hi,items ti"
3642 			" where hi.key_=ti.key_"
3643 				" and hi.hostid=" ZBX_FS_UI64
3644 				" and ti.itemid=" ZBX_FS_UI64,
3645 			hostid, titemid);
3646 
3647 	if (NULL != (row = DBfetch(result)))
3648 		ZBX_STR2UINT64(itemid, row[0]);
3649 	DBfree_result(result);
3650 
3651 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():" ZBX_FS_UI64, __function_name, itemid);
3652 
3653 	return itemid;
3654 }
3655 
3656 /******************************************************************************
3657  *                                                                            *
3658  * Function: DBcopy_graph_to_host                                             *
3659  *                                                                            *
3660  * Purpose: copy specified graph to host                                      *
3661  *                                                                            *
3662  * Parameters: graphid - graph identificator from database                    *
3663  *             hostid - host identificator from database                      *
3664  *                                                                            *
3665  * Author: Eugene Grigorjev, Alexander Vladishev                              *
3666  *                                                                            *
3667  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
3668  *                                                                            *
3669  ******************************************************************************/
DBcopy_graph_to_host(zbx_uint64_t hostid,zbx_uint64_t graphid,const char * name,int width,int height,double yaxismin,double yaxismax,unsigned char show_work_period,unsigned char show_triggers,unsigned char graphtype,unsigned char show_legend,unsigned char show_3d,double percent_left,double percent_right,unsigned char ymin_type,unsigned char ymax_type,zbx_uint64_t ymin_itemid,zbx_uint64_t ymax_itemid,unsigned char flags)3670 static void	DBcopy_graph_to_host(zbx_uint64_t hostid, zbx_uint64_t graphid,
3671 		const char *name, int width, int height, double yaxismin,
3672 		double yaxismax, unsigned char show_work_period,
3673 		unsigned char show_triggers, unsigned char graphtype,
3674 		unsigned char show_legend, unsigned char show_3d,
3675 		double percent_left, double percent_right,
3676 		unsigned char ymin_type, unsigned char ymax_type,
3677 		zbx_uint64_t ymin_itemid, zbx_uint64_t ymax_itemid,
3678 		unsigned char flags)
3679 {
3680 	const char	*__function_name = "DBcopy_graph_to_host";
3681 	DB_RESULT	result;
3682 	DB_ROW		row;
3683 	ZBX_GRAPH_ITEMS *gitems = NULL, *chd_gitems = NULL;
3684 	size_t		gitems_alloc = 0, gitems_num = 0,
3685 			chd_gitems_alloc = 0, chd_gitems_num = 0;
3686 	zbx_uint64_t	hst_graphid, hst_gitemid;
3687 	char		*sql = NULL, *name_esc, *color_esc;
3688 	size_t		sql_alloc = ZBX_KIBIBYTE, sql_offset, i;
3689 
3690 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
3691 
3692 	sql = zbx_malloc(sql, sql_alloc * sizeof(char));
3693 
3694 	name_esc = DBdyn_escape_string(name);
3695 
3696 	sql_offset = 0;
3697 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3698 			"select 0,dst.itemid,dst.key_,gi.drawtype,gi.sortorder,gi.color,gi.yaxisside,gi.calc_fnc,"
3699 				"gi.type,i.flags"
3700 			" from graphs_items gi,items i,items dst"
3701 			" where gi.itemid=i.itemid"
3702 				" and i.key_=dst.key_"
3703 				" and gi.graphid=" ZBX_FS_UI64
3704 				" and dst.hostid=" ZBX_FS_UI64
3705 			" order by dst.key_",
3706 			graphid, hostid);
3707 
3708 	DBget_graphitems(sql, &gitems, &gitems_alloc, &gitems_num);
3709 
3710 	result = DBselect(
3711 			"select distinct g.graphid"
3712 			" from graphs g,graphs_items gi,items i"
3713 			" where g.graphid=gi.graphid"
3714 				" and gi.itemid=i.itemid"
3715 				" and i.hostid=" ZBX_FS_UI64
3716 				" and g.name='%s'"
3717 				" and g.templateid is null",
3718 			hostid, name_esc);
3719 
3720 	/* compare graphs */
3721 	hst_graphid = 0;
3722 	while (NULL != (row = DBfetch(result)))
3723 	{
3724 		ZBX_STR2UINT64(hst_graphid, row[0]);
3725 
3726 		sql_offset = 0;
3727 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3728 				"select gi.gitemid,i.itemid,i.key_,gi.drawtype,gi.sortorder,gi.color,gi.yaxisside,"
3729 					"gi.calc_fnc,gi.type,i.flags"
3730 				" from graphs_items gi,items i"
3731 				" where gi.itemid=i.itemid"
3732 					" and gi.graphid=" ZBX_FS_UI64
3733 				" order by i.key_",
3734 				hst_graphid);
3735 
3736 		DBget_graphitems(sql, &chd_gitems, &chd_gitems_alloc, &chd_gitems_num);
3737 
3738 		if (SUCCEED == DBcmp_graphitems(gitems, gitems_num, chd_gitems, chd_gitems_num))
3739 			break;	/* found equal graph */
3740 
3741 		hst_graphid = 0;
3742 	}
3743 	DBfree_result(result);
3744 
3745 	sql_offset = 0;
3746 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
3747 
3748 	if (GRAPH_YAXIS_TYPE_ITEM_VALUE == ymin_type)
3749 		ymin_itemid = DBget_same_itemid(hostid, ymin_itemid);
3750 	else
3751 		ymin_itemid = 0;
3752 
3753 	if (GRAPH_YAXIS_TYPE_ITEM_VALUE == ymax_type)
3754 		ymax_itemid = DBget_same_itemid(hostid, ymax_itemid);
3755 	else
3756 		ymax_itemid = 0;
3757 
3758 	if (0 != hst_graphid)
3759 	{
3760 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3761 				"update graphs"
3762 				" set name='%s',"
3763 					"width=%d,"
3764 					"height=%d,"
3765 					"yaxismin=" ZBX_FS_DBL ","
3766 					"yaxismax=" ZBX_FS_DBL ","
3767 					"templateid=" ZBX_FS_UI64 ","
3768 					"show_work_period=%d,"
3769 					"show_triggers=%d,"
3770 					"graphtype=%d,"
3771 					"show_legend=%d,"
3772 					"show_3d=%d,"
3773 					"percent_left=" ZBX_FS_DBL ","
3774 					"percent_right=" ZBX_FS_DBL ","
3775 					"ymin_type=%d,"
3776 					"ymax_type=%d,"
3777 					"ymin_itemid=%s,"
3778 					"ymax_itemid=%s,"
3779 					"flags=%d"
3780 				" where graphid=" ZBX_FS_UI64 ";\n",
3781 				name_esc, width, height, yaxismin, yaxismax,
3782 				graphid, (int)show_work_period, (int)show_triggers,
3783 				(int)graphtype, (int)show_legend, (int)show_3d,
3784 				percent_left, percent_right, (int)ymin_type, (int)ymax_type,
3785 				DBsql_id_ins(ymin_itemid), DBsql_id_ins(ymax_itemid), (int)flags,
3786 				hst_graphid);
3787 
3788 		for (i = 0; i < gitems_num; i++)
3789 		{
3790 			color_esc = DBdyn_escape_string(gitems[i].color);
3791 
3792 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3793 					"update graphs_items"
3794 					" set drawtype=%d,"
3795 						"sortorder=%d,"
3796 						"color='%s',"
3797 						"yaxisside=%d,"
3798 						"calc_fnc=%d,"
3799 						"type=%d"
3800 					" where gitemid=" ZBX_FS_UI64 ";\n",
3801 					gitems[i].drawtype,
3802 					gitems[i].sortorder,
3803 					color_esc,
3804 					gitems[i].yaxisside,
3805 					gitems[i].calc_fnc,
3806 					gitems[i].type,
3807 					chd_gitems[i].gitemid);
3808 
3809 			zbx_free(color_esc);
3810 		}
3811 	}
3812 	else
3813 	{
3814 		hst_graphid = DBget_maxid("graphs");
3815 
3816 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3817 				"insert into graphs"
3818 				" (graphid,name,width,height,yaxismin,yaxismax,templateid,"
3819 				"show_work_period,show_triggers,graphtype,show_legend,"
3820 				"show_3d,percent_left,percent_right,ymin_type,ymax_type,"
3821 				"ymin_itemid,ymax_itemid,flags)"
3822 				" values (" ZBX_FS_UI64 ",'%s',%d,%d," ZBX_FS_DBL ","
3823 				ZBX_FS_DBL "," ZBX_FS_UI64 ",%d,%d,%d,%d,%d," ZBX_FS_DBL ","
3824 				ZBX_FS_DBL ",%d,%d,%s,%s,%d);\n",
3825 				hst_graphid, name_esc, width, height, yaxismin, yaxismax,
3826 				graphid, (int)show_work_period, (int)show_triggers,
3827 				(int)graphtype, (int)show_legend, (int)show_3d,
3828 				percent_left, percent_right, (int)ymin_type, (int)ymax_type,
3829 				DBsql_id_ins(ymin_itemid), DBsql_id_ins(ymax_itemid), (int)flags);
3830 
3831 		hst_gitemid = DBget_maxid_num("graphs_items", gitems_num);
3832 
3833 		for (i = 0; i < gitems_num; i++)
3834 		{
3835 			color_esc = DBdyn_escape_string(gitems[i].color);
3836 
3837 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3838 					"insert into graphs_items (gitemid,graphid,itemid,drawtype,"
3839 					"sortorder,color,yaxisside,calc_fnc,type)"
3840 					" values (" ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64
3841 					",%d,%d,'%s',%d,%d,%d);\n",
3842 					hst_gitemid, hst_graphid, gitems[i].itemid,
3843 					gitems[i].drawtype, gitems[i].sortorder, color_esc,
3844 					gitems[i].yaxisside, gitems[i].calc_fnc, gitems[i].type);
3845 			hst_gitemid++;
3846 
3847 			zbx_free(color_esc);
3848 		}
3849 	}
3850 
3851 	zbx_free(name_esc);
3852 
3853 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
3854 
3855 	if (sql_offset > 16)	/* In ORACLE always present begin..end; */
3856 		DBexecute("%s", sql);
3857 
3858 	zbx_free(gitems);
3859 	zbx_free(chd_gitems);
3860 	zbx_free(sql);
3861 
3862 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
3863 }
3864 
3865 /******************************************************************************
3866  *                                                                            *
3867  * Function: DBcopy_template_graphs                                           *
3868  *                                                                            *
3869  * Purpose: copy graphs from template to host                                 *
3870  *                                                                            *
3871  * Parameters: hostid      - [IN] host identificator from database            *
3872  *             templateids - [IN] array of template IDs                       *
3873  *                                                                            *
3874  * Author: Eugene Grigorjev                                                   *
3875  *                                                                            *
3876  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
3877  *                                                                            *
3878  ******************************************************************************/
DBcopy_template_graphs(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)3879 static void	DBcopy_template_graphs(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
3880 {
3881 	const char	*__function_name = "DBcopy_template_graphs";
3882 	char		*sql = NULL;
3883 	size_t		sql_alloc = 512, sql_offset = 0;
3884 	DB_RESULT	result;
3885 	DB_ROW		row;
3886 	zbx_uint64_t	graphid, ymin_itemid, ymax_itemid;
3887 
3888 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
3889 
3890 	sql = zbx_malloc(sql, sql_alloc);
3891 
3892 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
3893 			"select distinct g.graphid,g.name,g.width,g.height,g.yaxismin,"
3894 				"g.yaxismax,g.show_work_period,g.show_triggers,"
3895 				"g.graphtype,g.show_legend,g.show_3d,g.percent_left,"
3896 				"g.percent_right,g.ymin_type,g.ymax_type,g.ymin_itemid,"
3897 				"g.ymax_itemid,g.flags"
3898 			" from graphs g,graphs_items gi,items i"
3899 			" where g.graphid=gi.graphid"
3900 				" and gi.itemid=i.itemid"
3901 				" and");
3902 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.hostid", templateids->values, templateids->values_num);
3903 
3904 	result = DBselect("%s", sql);
3905 
3906 	zbx_free(sql);
3907 
3908 	while (NULL != (row = DBfetch(result)))
3909 	{
3910 		ZBX_STR2UINT64(graphid, row[0]);
3911 		ZBX_DBROW2UINT64(ymin_itemid, row[15]);
3912 		ZBX_DBROW2UINT64(ymax_itemid, row[16]);
3913 
3914 		DBcopy_graph_to_host(hostid, graphid,
3915 				row[1],				/* name */
3916 				atoi(row[2]),			/* width */
3917 				atoi(row[3]),			/* height */
3918 				atof(row[4]),			/* yaxismin */
3919 				atof(row[5]),			/* yaxismax */
3920 				(unsigned char)atoi(row[6]),	/* show_work_period */
3921 				(unsigned char)atoi(row[7]),	/* show_triggers */
3922 				(unsigned char)atoi(row[8]),	/* graphtype */
3923 				(unsigned char)atoi(row[9]),	/* show_legend */
3924 				(unsigned char)atoi(row[10]),	/* show_3d */
3925 				atof(row[11]),			/* percent_left */
3926 				atof(row[12]),			/* percent_right */
3927 				(unsigned char)atoi(row[13]),	/* ymin_type */
3928 				(unsigned char)atoi(row[14]),	/* ymax_type */
3929 				ymin_itemid,
3930 				ymax_itemid,
3931 				(unsigned char)atoi(row[17]));	/* flags */
3932 	}
3933 	DBfree_result(result);
3934 
3935 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
3936 }
3937 
3938 typedef struct
3939 {
3940 	zbx_uint64_t		t_itemid;
3941 	zbx_uint64_t		h_itemid;
3942 	unsigned char		type;
3943 }
3944 httpstepitem_t;
3945 
3946 typedef struct
3947 {
3948 	zbx_uint64_t		httpstepid;
3949 	char			*name;
3950 	char			*url;
3951 	char			*posts;
3952 	char			*required;
3953 	char			*status_codes;
3954 	zbx_vector_ptr_t	httpstepitems;
3955 	int			no;
3956 	int			timeout;
3957 	char			*variables;
3958 	char			*headers;
3959 	unsigned char		follow_redirects;
3960 	unsigned char		retrieve_mode;
3961 }
3962 httpstep_t;
3963 
3964 typedef struct
3965 {
3966 	zbx_uint64_t		t_itemid;
3967 	zbx_uint64_t		h_itemid;
3968 	unsigned char		type;
3969 }
3970 httptestitem_t;
3971 
3972 typedef struct
3973 {
3974 	zbx_uint64_t		templateid;
3975 	zbx_uint64_t		httptestid;
3976 	zbx_uint64_t		t_applicationid;
3977 	zbx_uint64_t		h_applicationid;
3978 	char			*name;
3979 	char			*variables;
3980 	char			*agent;
3981 	char			*http_user;
3982 	char			*http_password;
3983 	char			*http_proxy;
3984 	zbx_vector_ptr_t	httpsteps;
3985 	zbx_vector_ptr_t	httptestitems;
3986 	int			delay;
3987 	int			retries;
3988 	char			*headers;
3989 	unsigned char		status;
3990 	unsigned char		authentication;
3991 }
3992 httptest_t;
3993 
3994 /******************************************************************************
3995  *                                                                            *
3996  * Function: DBget_httptests                                                  *
3997  *                                                                            *
3998  * Purpose: helper function for DCmass_add_history()                          *
3999  *                                                                            *
4000  ******************************************************************************/
DBget_httptests(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids,zbx_vector_ptr_t * httptests)4001 static void	DBget_httptests(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids, zbx_vector_ptr_t *httptests)
4002 {
4003 	const char		*__function_name = "DBget_httptests";
4004 
4005 	char			*sql = NULL;
4006 	size_t			sql_alloc = 512, sql_offset = 0;
4007 	DB_RESULT		result;
4008 	DB_ROW			row;
4009 	httptest_t		*httptest;
4010 	httpstep_t		*httpstep;
4011 	httptestitem_t		*httptestitem;
4012 	httpstepitem_t		*httpstepitem;
4013 	zbx_vector_uint64_t	httptestids;	/* the list of web scenarios which should be added to a host */
4014 	zbx_vector_uint64_t	applications;
4015 	zbx_vector_uint64_t	items;
4016 	zbx_uint64_t		httptestid, httpstepid, applicationid, itemid;
4017 	int			i, j, k;
4018 
4019 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
4020 
4021 	zbx_vector_uint64_create(&httptestids);
4022 	zbx_vector_uint64_create(&applications);
4023 	zbx_vector_uint64_create(&items);
4024 
4025 	sql = zbx_malloc(sql, sql_alloc);
4026 
4027 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
4028 			"select t.httptestid,t.name,t.applicationid,t.delay,t.status,t.variables,t.agent,"
4029 				"t.authentication,t.http_user,t.http_password,t.http_proxy,t.retries,h.httptestid,"
4030 				"t.headers"
4031 			" from httptest t"
4032 				" left join httptest h"
4033 					" on h.hostid=" ZBX_FS_UI64
4034 						" and h.name=t.name"
4035 			" where", hostid);
4036 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.hostid", templateids->values, templateids->values_num);
4037 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by t.httptestid");
4038 
4039 	result = DBselect("%s", sql);
4040 
4041 	while (NULL != (row = DBfetch(result)))
4042 	{
4043 		httptest = zbx_calloc(NULL, 1, sizeof(httptest_t));
4044 
4045 		ZBX_STR2UINT64(httptest->templateid, row[0]);
4046 		ZBX_DBROW2UINT64(httptest->httptestid, row[12]);
4047 		zbx_vector_ptr_create(&httptest->httpsteps);
4048 		zbx_vector_ptr_create(&httptest->httptestitems);
4049 
4050 		zbx_vector_ptr_append(httptests, httptest);
4051 
4052 		if (0 == httptest->httptestid)
4053 		{
4054 			httptest->name = zbx_strdup(NULL, row[1]);
4055 			ZBX_DBROW2UINT64(httptest->t_applicationid, row[2]);
4056 			httptest->delay = atoi(row[3]);
4057 			httptest->status = (unsigned char)atoi(row[4]);
4058 			httptest->variables = zbx_strdup(NULL, row[5]);
4059 			httptest->agent = zbx_strdup(NULL, row[6]);
4060 			httptest->authentication = (unsigned char)atoi(row[7]);
4061 			httptest->http_user = zbx_strdup(NULL, row[8]);
4062 			httptest->http_password = zbx_strdup(NULL, row[9]);
4063 			httptest->http_proxy = zbx_strdup(NULL, row[10]);
4064 			httptest->retries = atoi(row[11]);
4065 			httptest->headers = zbx_strdup(NULL, row[13]);
4066 
4067 			zbx_vector_uint64_append(&httptestids, httptest->templateid);
4068 
4069 			if (0 != httptest->t_applicationid)
4070 				zbx_vector_uint64_append(&applications, httptest->t_applicationid);
4071 		}
4072 	}
4073 	DBfree_result(result);
4074 
4075 	/* web scenario steps */
4076 	if (0 != httptestids.values_num)
4077 	{
4078 		httptest = NULL;
4079 
4080 		sql_offset = 0;
4081 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
4082 				"select httpstepid,httptestid,name,no,url,timeout,posts,required,status_codes,"
4083 					"variables,follow_redirects,retrieve_mode,headers"
4084 				" from httpstep"
4085 				" where");
4086 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid",
4087 				httptestids.values, httptestids.values_num);
4088 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by httptestid");
4089 
4090 		result = DBselect("%s", sql);
4091 
4092 		while (NULL != (row = DBfetch(result)))
4093 		{
4094 			ZBX_STR2UINT64(httptestid, row[1]);
4095 
4096 			if (NULL == httptest || httptest->templateid != httptestid)
4097 			{
4098 				if (FAIL == (i = zbx_vector_ptr_bsearch(httptests, &httptestid,
4099 						ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
4100 				{
4101 					THIS_SHOULD_NEVER_HAPPEN;
4102 					continue;
4103 				}
4104 
4105 				httptest = (httptest_t *)httptests->values[i];
4106 			}
4107 
4108 			httpstep = zbx_malloc(NULL, sizeof(httptest_t));
4109 
4110 			ZBX_STR2UINT64(httpstep->httpstepid, row[0]);
4111 			httpstep->name = zbx_strdup(NULL, row[2]);
4112 			httpstep->no = atoi(row[3]);
4113 			httpstep->url = zbx_strdup(NULL, row[4]);
4114 			httpstep->timeout = atoi(row[5]);
4115 			httpstep->posts = zbx_strdup(NULL, row[6]);
4116 			httpstep->required = zbx_strdup(NULL, row[7]);
4117 			httpstep->status_codes = zbx_strdup(NULL, row[8]);
4118 			httpstep->variables = zbx_strdup(NULL, row[9]);
4119 			httpstep->follow_redirects = atoi(row[10]);
4120 			httpstep->retrieve_mode = atoi(row[11]);
4121 			httpstep->headers = zbx_strdup(NULL, row[12]);
4122 			zbx_vector_ptr_create(&httpstep->httpstepitems);
4123 
4124 			zbx_vector_ptr_append(&httptest->httpsteps, httpstep);
4125 		}
4126 		DBfree_result(result);
4127 
4128 		for (i = 0; i < httptests->values_num; i++)
4129 		{
4130 			httptest = (httptest_t *)httptests->values[i];
4131 			zbx_vector_ptr_sort(&httptest->httpsteps, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
4132 		}
4133 	}
4134 
4135 	/* applications */
4136 	if (0 != applications.values_num)
4137 	{
4138 		zbx_vector_uint64_sort(&applications, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4139 		zbx_vector_uint64_uniq(&applications, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4140 
4141 		sql_offset = 0;
4142 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
4143 				"select t.applicationid,h.applicationid"
4144 				" from applications t"
4145 					" join applications h"
4146 						" on h.hostid=" ZBX_FS_UI64
4147 							" and h.name=t.name"
4148 				" where", hostid);
4149 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.applicationid",
4150 				applications.values, applications.values_num);
4151 
4152 		result = DBselect("%s", sql);
4153 
4154 		while (NULL != (row = DBfetch(result)))
4155 		{
4156 			ZBX_STR2UINT64(applicationid, row[0]);
4157 
4158 			for (i = 0; i < httptests->values_num; i++)
4159 			{
4160 				httptest = (httptest_t *)httptests->values[i];
4161 
4162 				if (httptest->t_applicationid == applicationid)
4163 					ZBX_STR2UINT64(httptest->h_applicationid, row[1]);
4164 			}
4165 		}
4166 		DBfree_result(result);
4167 	}
4168 
4169 	/* web scenario items */
4170 	if (0 != httptestids.values_num)
4171 	{
4172 		httptest = NULL;
4173 
4174 		sql_offset = 0;
4175 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
4176 				"select httptestid,itemid,type"
4177 				" from httptestitem"
4178 				" where");
4179 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "httptestid",
4180 				httptestids.values, httptestids.values_num);
4181 
4182 		result = DBselect("%s", sql);
4183 
4184 		while (NULL != (row = DBfetch(result)))
4185 		{
4186 			ZBX_STR2UINT64(httptestid, row[0]);
4187 
4188 			if (NULL == httptest || httptest->templateid != httptestid)
4189 			{
4190 				if (FAIL == (i = zbx_vector_ptr_bsearch(httptests, &httptestid,
4191 						ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
4192 				{
4193 					THIS_SHOULD_NEVER_HAPPEN;
4194 					continue;
4195 				}
4196 
4197 				httptest = (httptest_t *)httptests->values[i];
4198 			}
4199 
4200 			httptestitem = zbx_calloc(NULL, 1, sizeof(httptestitem_t));
4201 
4202 			ZBX_STR2UINT64(httptestitem->t_itemid, row[1]);
4203 			httptestitem->type = (unsigned char)atoi(row[2]);
4204 
4205 			zbx_vector_ptr_append(&httptest->httptestitems, httptestitem);
4206 
4207 			zbx_vector_uint64_append(&items, httptestitem->t_itemid);
4208 		}
4209 		DBfree_result(result);
4210 	}
4211 
4212 	/* web scenario step items */
4213 	if (0 != httptestids.values_num)
4214 	{
4215 		httptest = NULL;
4216 		httpstep = NULL;
4217 
4218 		sql_offset = 0;
4219 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
4220 				"select hs.httptestid,hsi.httpstepid,hsi.itemid,hsi.type"
4221 				" from httpstepitem hsi"
4222 					" join httpstep hs"
4223 						" on");
4224 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hs.httptestid",
4225 				httptestids.values, httptestids.values_num);
4226 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
4227 							" and hs.httpstepid=hsi.httpstepid"
4228 				" order by hs.httptestid,hsi.httpstepid");
4229 
4230 		result = DBselect("%s", sql);
4231 
4232 		while (NULL != (row = DBfetch(result)))
4233 		{
4234 			ZBX_STR2UINT64(httptestid, row[0]);
4235 			ZBX_STR2UINT64(httpstepid, row[1]);
4236 
4237 			if (NULL == httptest || httptest->templateid != httptestid)
4238 			{
4239 				if (FAIL == (i = zbx_vector_ptr_bsearch(httptests, &httptestid,
4240 						ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
4241 				{
4242 					THIS_SHOULD_NEVER_HAPPEN;
4243 					continue;
4244 				}
4245 
4246 				httptest = (httptest_t *)httptests->values[i];
4247 				httpstep = NULL;
4248 			}
4249 
4250 			if (NULL == httpstep || httpstep->httpstepid != httpstepid)
4251 			{
4252 				if (FAIL == (i = zbx_vector_ptr_bsearch(&httptest->httpsteps, &httpstepid,
4253 						ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
4254 				{
4255 					THIS_SHOULD_NEVER_HAPPEN;
4256 					continue;
4257 				}
4258 
4259 				httpstep = (httpstep_t *)httptest->httpsteps.values[i];
4260 			}
4261 
4262 			httpstepitem = zbx_calloc(NULL, 1, sizeof(httpstepitem_t));
4263 
4264 			ZBX_STR2UINT64(httpstepitem->t_itemid, row[2]);
4265 			httpstepitem->type = (unsigned char)atoi(row[3]);
4266 
4267 			zbx_vector_ptr_append(&httpstep->httpstepitems, httpstepitem);
4268 
4269 			zbx_vector_uint64_append(&items, httpstepitem->t_itemid);
4270 		}
4271 		DBfree_result(result);
4272 	}
4273 
4274 	/* items */
4275 	if (0 != items.values_num)
4276 	{
4277 		zbx_vector_uint64_sort(&items, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4278 
4279 		sql_offset = 0;
4280 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
4281 				"select t.itemid,h.itemid"
4282 				" from items t"
4283 					" join items h"
4284 						" on h.hostid=" ZBX_FS_UI64
4285 							" and h.key_=t.key_"
4286 				" where", hostid);
4287 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.itemid",
4288 				items.values, items.values_num);
4289 
4290 		result = DBselect("%s", sql);
4291 
4292 		while (NULL != (row = DBfetch(result)))
4293 		{
4294 			ZBX_STR2UINT64(itemid, row[0]);
4295 
4296 			for (i = 0; i < httptests->values_num; i++)
4297 			{
4298 				httptest = (httptest_t *)httptests->values[i];
4299 
4300 				for (j = 0; j < httptest->httptestitems.values_num; j++)
4301 				{
4302 					httptestitem = (httptestitem_t *)httptest->httptestitems.values[j];
4303 
4304 					if (httptestitem->t_itemid == itemid)
4305 						ZBX_STR2UINT64(httptestitem->h_itemid, row[1]);
4306 				}
4307 
4308 				for (j = 0; j < httptest->httpsteps.values_num; j++)
4309 				{
4310 					httpstep = (httpstep_t *)httptest->httpsteps.values[j];
4311 
4312 					for (k = 0; k < httpstep->httpstepitems.values_num; k++)
4313 					{
4314 						httpstepitem = (httpstepitem_t *)httpstep->httpstepitems.values[k];
4315 
4316 						if (httpstepitem->t_itemid == itemid)
4317 							ZBX_STR2UINT64(httpstepitem->h_itemid, row[1]);
4318 					}
4319 				}
4320 			}
4321 		}
4322 		DBfree_result(result);
4323 	}
4324 
4325 	zbx_free(sql);
4326 
4327 	zbx_vector_uint64_destroy(&items);
4328 	zbx_vector_uint64_destroy(&applications);
4329 	zbx_vector_uint64_destroy(&httptestids);
4330 
4331 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
4332 }
4333 
4334 /******************************************************************************
4335  *                                                                            *
4336  * Function: DBsave_httptests                                                 *
4337  *                                                                            *
4338  * Purpose: helper function for DCmass_add_history()                          *
4339  *                                                                            *
4340  ******************************************************************************/
DBsave_httptests(zbx_uint64_t hostid,zbx_vector_ptr_t * httptests)4341 static void	DBsave_httptests(zbx_uint64_t hostid, zbx_vector_ptr_t *httptests)
4342 {
4343 	char		*sql = NULL;
4344 	size_t		sql_alloc = 512, sql_offset = 0;
4345 	httptest_t	*httptest;
4346 	httpstep_t	*httpstep;
4347 	httptestitem_t	*httptestitem;
4348 	httpstepitem_t	*httpstepitem;
4349 	zbx_uint64_t	httptestid = 0, httpstepid = 0, httptestitemid = 0, httpstepitemid = 0;
4350 	int		i, j, k, num_httptests = 0, num_httpsteps = 0, num_httptestitems = 0, num_httpstepitems = 0;
4351 	zbx_db_insert_t	db_insert_htest, db_insert_hstep, db_insert_htitem, db_insert_hsitem;
4352 
4353 	if (0 == httptests->values_num)
4354 		return;
4355 
4356 	for (i = 0; i < httptests->values_num; i++)
4357 	{
4358 		httptest = (httptest_t *)httptests->values[i];
4359 
4360 		if (0 == httptest->httptestid)
4361 		{
4362 			num_httptests++;
4363 			num_httpsteps += httptest->httpsteps.values_num;
4364 			num_httptestitems += httptest->httptestitems.values_num;
4365 
4366 			for (j = 0; j < httptest->httpsteps.values_num; j++)
4367 			{
4368 				httpstep = (httpstep_t *)httptest->httpsteps.values[j];
4369 
4370 				num_httpstepitems += httpstep->httpstepitems.values_num;
4371 			}
4372 		}
4373 	}
4374 
4375 	if (0 != num_httptests)
4376 	{
4377 		httptestid = DBget_maxid_num("httptest", num_httptests);
4378 
4379 		zbx_db_insert_prepare(&db_insert_htest, "httptest", "httptestid", "name", "applicationid", "delay",
4380 				"status", "variables", "agent", "authentication", "http_user", "http_password",
4381 				"http_proxy", "retries", "hostid", "templateid", "headers", NULL);
4382 	}
4383 
4384 	if (httptests->values_num != num_httptests)
4385 		sql = zbx_malloc(sql, sql_alloc);
4386 
4387 	if (0 != num_httpsteps)
4388 	{
4389 		httpstepid = DBget_maxid_num("httpstep", num_httpsteps);
4390 
4391 		zbx_db_insert_prepare(&db_insert_hstep, "httpstep", "httpstepid", "httptestid", "name", "no", "url",
4392 				"timeout", "posts", "required", "status_codes", "variables", "follow_redirects",
4393 				"retrieve_mode", "headers", NULL);
4394 	}
4395 
4396 	if (0 != num_httptestitems)
4397 	{
4398 		httptestitemid = DBget_maxid_num("httptestitem", num_httptestitems);
4399 
4400 		zbx_db_insert_prepare(&db_insert_htitem, "httptestitem", "httptestitemid", "httptestid", "itemid",
4401 				"type", NULL);
4402 	}
4403 
4404 	if (0 != num_httpstepitems)
4405 	{
4406 		httpstepitemid = DBget_maxid_num("httpstepitem", num_httpstepitems);
4407 
4408 		zbx_db_insert_prepare(&db_insert_hsitem, "httpstepitem", "httpstepitemid", "httpstepid", "itemid",
4409 				"type", NULL);
4410 	}
4411 
4412 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
4413 
4414 	for (i = 0; i < httptests->values_num; i++)
4415 	{
4416 		httptest = (httptest_t *)httptests->values[i];
4417 
4418 		if (0 == httptest->httptestid)
4419 		{
4420 			httptest->httptestid = httptestid++;
4421 
4422 			zbx_db_insert_add_values(&db_insert_htest, httptest->httptestid, httptest->name,
4423 					httptest->h_applicationid, httptest->delay, (int)httptest->status,
4424 					httptest->variables, httptest->agent, (int)httptest->authentication,
4425 					httptest->http_user, httptest->http_password, httptest->http_proxy,
4426 					httptest->retries, hostid, httptest->templateid, httptest->headers);
4427 
4428 			for (j = 0; j < httptest->httpsteps.values_num; j++)
4429 			{
4430 				httpstep = (httpstep_t *)httptest->httpsteps.values[j];
4431 
4432 				zbx_db_insert_add_values(&db_insert_hstep, httpstepid, httptest->httptestid,
4433 						httpstep->name, httpstep->no, httpstep->url, httpstep->timeout,
4434 						httpstep->posts, httpstep->required, httpstep->status_codes,
4435 						httpstep->variables, httpstep->follow_redirects,
4436 						httpstep->retrieve_mode, httpstep->headers);
4437 
4438 				for (k = 0; k < httpstep->httpstepitems.values_num; k++)
4439 				{
4440 					httpstepitem = (httpstepitem_t *)httpstep->httpstepitems.values[k];
4441 
4442 					zbx_db_insert_add_values(&db_insert_hsitem,  httpstepitemid, httpstepid,
4443 							httpstepitem->h_itemid, (int)httpstepitem->type);
4444 
4445 					httpstepitemid++;
4446 				}
4447 
4448 				httpstepid++;
4449 			}
4450 
4451 			for (j = 0; j < httptest->httptestitems.values_num; j++)
4452 			{
4453 				httptestitem = (httptestitem_t *)httptest->httptestitems.values[j];
4454 
4455 				zbx_db_insert_add_values(&db_insert_htitem, httptestitemid, httptest->httptestid,
4456 						httptestitem->h_itemid, (int)httptestitem->type);
4457 
4458 				httptestitemid++;
4459 			}
4460 		}
4461 		else
4462 		{
4463 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
4464 					"update httptest"
4465 					" set templateid=" ZBX_FS_UI64
4466 					" where httptestid=" ZBX_FS_UI64 ";\n",
4467 					httptest->templateid, httptest->httptestid);
4468 		}
4469 	}
4470 
4471 	if (0 != num_httptests)
4472 	{
4473 		zbx_db_insert_execute(&db_insert_htest);
4474 		zbx_db_insert_clean(&db_insert_htest);
4475 	}
4476 
4477 	if (0 != num_httpsteps)
4478 	{
4479 		zbx_db_insert_execute(&db_insert_hstep);
4480 		zbx_db_insert_clean(&db_insert_hstep);
4481 	}
4482 
4483 	if (0 != num_httptestitems)
4484 	{
4485 		zbx_db_insert_execute(&db_insert_htitem);
4486 		zbx_db_insert_clean(&db_insert_htitem);
4487 	}
4488 
4489 	if (0 != num_httpstepitems)
4490 	{
4491 		zbx_db_insert_execute(&db_insert_hsitem);
4492 		zbx_db_insert_clean(&db_insert_hsitem);
4493 	}
4494 
4495 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
4496 
4497 	if (16 < sql_offset)
4498 		DBexecute("%s", sql);
4499 
4500 	zbx_free(sql);
4501 }
4502 
4503 /******************************************************************************
4504  *                                                                            *
4505  * Function: clean_httptests                                                  *
4506  *                                                                            *
4507  * Purpose: helper function for DCmass_add_history()                          *
4508  *                                                                            *
4509  ******************************************************************************/
clean_httptests(zbx_vector_ptr_t * httptests)4510 static void	clean_httptests(zbx_vector_ptr_t *httptests)
4511 {
4512 	httptest_t	*httptest;
4513 	httpstep_t	*httpstep;
4514 	int		i, j, k;
4515 
4516 	for (i = 0; i < httptests->values_num; i++)
4517 	{
4518 		httptest = (httptest_t *)httptests->values[i];
4519 
4520 		zbx_free(httptest->http_proxy);
4521 		zbx_free(httptest->http_password);
4522 		zbx_free(httptest->http_user);
4523 		zbx_free(httptest->agent);
4524 		zbx_free(httptest->variables);
4525 		zbx_free(httptest->name);
4526 		zbx_free(httptest->headers);
4527 
4528 		for (j = 0; j < httptest->httpsteps.values_num; j++)
4529 		{
4530 			httpstep = (httpstep_t *)httptest->httpsteps.values[j];
4531 
4532 			zbx_free(httpstep->status_codes);
4533 			zbx_free(httpstep->required);
4534 			zbx_free(httpstep->posts);
4535 			zbx_free(httpstep->url);
4536 			zbx_free(httpstep->name);
4537 			zbx_free(httpstep->variables);
4538 			zbx_free(httpstep->headers);
4539 
4540 			for (k = 0; k < httpstep->httpstepitems.values_num; k++)
4541 				zbx_free(httpstep->httpstepitems.values[k]);
4542 
4543 			zbx_vector_ptr_destroy(&httpstep->httpstepitems);
4544 
4545 			zbx_free(httpstep);
4546 		}
4547 
4548 		zbx_vector_ptr_destroy(&httptest->httpsteps);
4549 
4550 		for (j = 0; j < httptest->httptestitems.values_num; j++)
4551 			zbx_free(httptest->httptestitems.values[j]);
4552 
4553 		zbx_vector_ptr_destroy(&httptest->httptestitems);
4554 
4555 		zbx_free(httptest);
4556 	}
4557 }
4558 
4559 /******************************************************************************
4560  *                                                                            *
4561  * Function: DBcopy_template_httptests                                        *
4562  *                                                                            *
4563  * Purpose: copy web scenarios from template to host                          *
4564  *                                                                            *
4565  * Parameters: hostid      - [IN] host identificator from database            *
4566  *             templateids - [IN] array of template IDs                       *
4567  *                                                                            *
4568  ******************************************************************************/
DBcopy_template_httptests(zbx_uint64_t hostid,const zbx_vector_uint64_t * templateids)4569 static void	DBcopy_template_httptests(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids)
4570 {
4571 	const char		*__function_name = "DBcopy_template_httptests";
4572 	zbx_vector_ptr_t	httptests;
4573 
4574 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
4575 
4576 	zbx_vector_ptr_create(&httptests);
4577 
4578 	DBget_httptests(hostid, templateids, &httptests);
4579 	DBsave_httptests(hostid, &httptests);
4580 
4581 	clean_httptests(&httptests);
4582 	zbx_vector_ptr_destroy(&httptests);
4583 
4584 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
4585 }
4586 
4587 /******************************************************************************
4588  *                                                                            *
4589  * Function: DBcopy_template_elements                                         *
4590  *                                                                            *
4591  * Purpose: copy elements from specified template                             *
4592  *                                                                            *
4593  * Parameters: hostid          - [IN] host identificator from database        *
4594  *             lnk_templateids - [IN] array of template IDs                   *
4595  *                                                                            *
4596  * Return value: upon successful completion return SUCCEED                    *
4597  *                                                                            *
4598  ******************************************************************************/
DBcopy_template_elements(zbx_uint64_t hostid,zbx_vector_uint64_t * lnk_templateids,char ** error)4599 int	DBcopy_template_elements(zbx_uint64_t hostid, zbx_vector_uint64_t *lnk_templateids, char **error)
4600 {
4601 	const char		*__function_name = "DBcopy_template_elements";
4602 	zbx_vector_uint64_t	templateids;
4603 	zbx_uint64_t		hosttemplateid;
4604 	int			i, res = SUCCEED;
4605 	char			*template_names, err[MAX_STRING_LEN];
4606 
4607 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
4608 
4609 	zbx_vector_uint64_create(&templateids);
4610 
4611 	get_templates_by_hostid(hostid, &templateids);
4612 
4613 	for (i = 0; i < lnk_templateids->values_num; i++)
4614 	{
4615 		if (FAIL != zbx_vector_uint64_search(&templateids, lnk_templateids->values[i],
4616 				ZBX_DEFAULT_UINT64_COMPARE_FUNC))
4617 		{
4618 			/* template already linked */
4619 			zbx_vector_uint64_remove(lnk_templateids, i--);
4620 		}
4621 		else
4622 			zbx_vector_uint64_append(&templateids, lnk_templateids->values[i]);
4623 	}
4624 
4625 	/* all templates already linked */
4626 	if (0 == lnk_templateids->values_num)
4627 		goto clean;
4628 
4629 	zbx_vector_uint64_sort(&templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4630 
4631 	if (SUCCEED != (res = validate_linked_templates(&templateids, err, sizeof(err))))
4632 	{
4633 		template_names = get_template_names(lnk_templateids);
4634 
4635 		*error = zbx_dsprintf(NULL, "%s to host \"%s\": %s", template_names, zbx_host_string(hostid), err);
4636 
4637 		zbx_free(template_names);
4638 		goto clean;
4639 	}
4640 
4641 	if (SUCCEED != (res = validate_host(hostid, lnk_templateids, err, sizeof(err))))
4642 	{
4643 		template_names = get_template_names(lnk_templateids);
4644 
4645 		*error = zbx_dsprintf(NULL, "%s to host \"%s\": %s", template_names, zbx_host_string(hostid), err);
4646 
4647 		zbx_free(template_names);
4648 		goto clean;
4649 	}
4650 
4651 	hosttemplateid = DBget_maxid_num("hosts_templates", lnk_templateids->values_num);
4652 
4653 	for (i = 0; i < lnk_templateids->values_num; i++)
4654 	{
4655 		DBexecute("insert into hosts_templates (hosttemplateid,hostid,templateid)"
4656 				" values (" ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64 ")",
4657 				hosttemplateid++, hostid, lnk_templateids->values[i]);
4658 	}
4659 
4660 	DBcopy_template_applications(hostid, lnk_templateids);
4661 	DBcopy_template_items(hostid, lnk_templateids);
4662 	DBcopy_template_application_prototypes(hostid, lnk_templateids);
4663 	DBcopy_template_item_application_prototypes(hostid, lnk_templateids);
4664 	DBcopy_template_host_prototypes(hostid, lnk_templateids);
4665 	if (SUCCEED == (res = DBcopy_template_triggers(hostid, lnk_templateids)))
4666 	{
4667 		DBcopy_template_graphs(hostid, lnk_templateids);
4668 		DBcopy_template_httptests(hostid, lnk_templateids);
4669 	}
4670 clean:
4671 	zbx_vector_uint64_destroy(&templateids);
4672 
4673 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res));
4674 
4675 	return res;
4676 }
4677 
4678 /******************************************************************************
4679  *                                                                            *
4680  * Function: DBdelete_hosts                                                   *
4681  *                                                                            *
4682  * Purpose: delete hosts from database with all elements                      *
4683  *                                                                            *
4684  * Parameters: hostids - [IN] host identificators from database               *
4685  *                                                                            *
4686  ******************************************************************************/
DBdelete_hosts(zbx_vector_uint64_t * hostids)4687 void	DBdelete_hosts(zbx_vector_uint64_t *hostids)
4688 {
4689 	const char		*__function_name = "DBdelete_hosts";
4690 
4691 	zbx_vector_uint64_t	itemids, httptestids, selementids;
4692 	char			*sql = NULL;
4693 	size_t			sql_alloc = 0, sql_offset;
4694 	int			i;
4695 
4696 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
4697 
4698 	if (SUCCEED != DBlock_hostids(hostids))
4699 		goto out;
4700 
4701 	zbx_vector_uint64_create(&httptestids);
4702 	zbx_vector_uint64_create(&selementids);
4703 
4704 	/* delete web tests */
4705 
4706 	sql_offset = 0;
4707 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
4708 			"select httptestid"
4709 			" from httptest"
4710 			" where");
4711 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids->values, hostids->values_num);
4712 
4713 	DBselect_uint64(sql, &httptestids);
4714 
4715 	DBdelete_httptests(&httptestids);
4716 
4717 	zbx_vector_uint64_destroy(&httptestids);
4718 
4719 	/* delete items -> triggers -> graphs */
4720 
4721 	zbx_vector_uint64_create(&itemids);
4722 
4723 	sql_offset = 0;
4724 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
4725 			"select itemid"
4726 			" from items"
4727 			" where");
4728 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids->values, hostids->values_num);
4729 
4730 	DBselect_uint64(sql, &itemids);
4731 
4732 	DBdelete_items(&itemids);
4733 
4734 	zbx_vector_uint64_destroy(&itemids);
4735 
4736 	sql_offset = 0;
4737 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
4738 
4739 	/* delete host from maps */
4740 	DBget_sysmapelements_by_element_type_ids(&selementids, SYSMAP_ELEMENT_TYPE_HOST, hostids);
4741 	if (0 != selementids.values_num)
4742 	{
4743 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from sysmaps_elements where");
4744 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "selementid", selementids.values,
4745 				selementids.values_num);
4746 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
4747 	}
4748 
4749 	/* delete action conditions */
4750 	for (i = 0; i < hostids->values_num; i++)
4751 		DBdelete_action_conditions(CONDITION_TYPE_HOST, hostids->values[i]);
4752 
4753 	/* delete host */
4754 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from hosts where");
4755 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids->values, hostids->values_num);
4756 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
4757 
4758 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
4759 
4760 	DBexecute("%s", sql);
4761 
4762 	zbx_free(sql);
4763 
4764 	zbx_vector_uint64_destroy(&selementids);
4765 out:
4766 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
4767 }
4768 
4769 /******************************************************************************
4770  *                                                                            *
4771  * Function: DBdelete_hosts_with_prototypes                                   *
4772  *                                                                            *
4773  * Purpose: delete hosts from database, check if there are any host           *
4774  *          prototypes and delete them first                                  *
4775  *                                                                            *
4776  * Parameters: hostids - [IN] host identificators from database               *
4777  *                                                                            *
4778  ******************************************************************************/
DBdelete_hosts_with_prototypes(zbx_vector_uint64_t * hostids)4779 void	DBdelete_hosts_with_prototypes(zbx_vector_uint64_t *hostids)
4780 {
4781 	const char		*__function_name = "DBdelete_hosts_with_prototypes";
4782 
4783 	zbx_vector_uint64_t	host_prototypeids;
4784 	char			*sql = NULL;
4785 	size_t			sql_alloc = 0, sql_offset = 0;
4786 
4787 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
4788 
4789 	zbx_vector_uint64_create(&host_prototypeids);
4790 
4791 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
4792 			"select hd.hostid"
4793 			" from items i,host_discovery hd"
4794 			" where i.itemid=hd.parent_itemid"
4795 				" and");
4796 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.hostid", hostids->values, hostids->values_num);
4797 
4798 	DBselect_uint64(sql, &host_prototypeids);
4799 
4800 	DBdelete_host_prototypes(&host_prototypeids);
4801 
4802 	zbx_free(sql);
4803 	zbx_vector_uint64_destroy(&host_prototypeids);
4804 
4805 	DBdelete_hosts(hostids);
4806 
4807 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
4808 }
4809 
4810 /******************************************************************************
4811  *                                                                            *
4812  * Function: DBadd_interface                                                  *
4813  *                                                                            *
4814  * Purpose: add new interface to specified host                               *
4815  *                                                                            *
4816  * Parameters: hostid - [IN] host identificator from database                 *
4817  *             type   - [IN] new interface type                               *
4818  *             useip  - [IN] how to connect to the host 0/1 - DNS/IP          *
4819  *             ip     - [IN] IP address                                       *
4820  *             dns    - [IN] DNS address                                      *
4821  *             port   - [IN] port                                             *
4822  *                                                                            *
4823  * Return value: upon successful completion return interface identificator    *
4824  *                                                                            *
4825  * Author: Alexander Vladishev                                                *
4826  *                                                                            *
4827  * Comments:                                                                  *
4828  *                                                                            *
4829  ******************************************************************************/
DBadd_interface(zbx_uint64_t hostid,unsigned char type,unsigned char useip,const char * ip,const char * dns,unsigned short port)4830 zbx_uint64_t	DBadd_interface(zbx_uint64_t hostid, unsigned char type,
4831 		unsigned char useip, const char *ip, const char *dns, unsigned short port)
4832 {
4833 	const char	*__function_name = "DBadd_interface";
4834 
4835 	DB_RESULT	result;
4836 	DB_ROW		row;
4837 	char		*ip_esc, *dns_esc, *tmp = NULL;
4838 	zbx_uint64_t	interfaceid = 0;
4839 	unsigned char	main_ = 1, db_main, db_useip;
4840 	unsigned short	db_port;
4841 	const char	*db_ip, *db_dns;
4842 
4843 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
4844 
4845 	result = DBselect(
4846 			"select interfaceid,useip,ip,dns,port,main"
4847 			" from interface"
4848 			" where hostid=" ZBX_FS_UI64
4849 				" and type=%d",
4850 			hostid, (int)type);
4851 
4852 	while (NULL != (row = DBfetch(result)))
4853 	{
4854 		db_useip = (unsigned char)atoi(row[1]);
4855 		db_ip = row[2];
4856 		db_dns = row[3];
4857 		db_main = (unsigned char)atoi(row[5]);
4858 		if (1 == db_main)
4859 			main_ = 0;
4860 
4861 		if (db_useip != useip)
4862 			continue;
4863 
4864 		if (useip && 0 != strcmp(db_ip, ip))
4865 			continue;
4866 
4867 		if (!useip && 0 != strcmp(db_dns, dns))
4868 			continue;
4869 
4870 		zbx_free(tmp);
4871 		tmp = strdup(row[4]);
4872 		substitute_simple_macros(NULL, NULL, NULL, NULL, &hostid, NULL, NULL,  NULL,
4873 				&tmp, MACRO_TYPE_COMMON, NULL, 0);
4874 		if (FAIL == is_ushort(tmp, &db_port) || db_port != port)
4875 			continue;
4876 
4877 		ZBX_STR2UINT64(interfaceid, row[0]);
4878 		break;
4879 	}
4880 	DBfree_result(result);
4881 
4882 	zbx_free(tmp);
4883 
4884 	if (0 != interfaceid)
4885 		goto out;
4886 
4887 	ip_esc = DBdyn_escape_field("interface", "ip", ip);
4888 	dns_esc = DBdyn_escape_field("interface", "dns", dns);
4889 
4890 	interfaceid = DBget_maxid("interface");
4891 
4892 	DBexecute("insert into interface"
4893 			" (interfaceid,hostid,main,type,useip,ip,dns,port)"
4894 		" values"
4895 			" (" ZBX_FS_UI64 "," ZBX_FS_UI64 ",%d,%d,%d,'%s','%s',%d)",
4896 		interfaceid, hostid, (int)main_, (int)type, (int)useip, ip_esc, dns_esc, (int)port);
4897 
4898 	zbx_free(dns_esc);
4899 	zbx_free(ip_esc);
4900 out:
4901 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():" ZBX_FS_UI64, __function_name, interfaceid);
4902 
4903 	return interfaceid;
4904 }
4905 
4906 /******************************************************************************
4907  *                                                                            *
4908  * Function: DBdelete_groups_validate                                         *
4909  *                                                                            *
4910  * Purpose: removes the groupids from the list which cannot be deleted        *
4911  *          (host or template can remain without groups or it's an internal   *
4912  *          group or it's used by a host prototype)                           *
4913  *                                                                            *
4914  ******************************************************************************/
DBdelete_groups_validate(zbx_vector_uint64_t * groupids)4915 static void	DBdelete_groups_validate(zbx_vector_uint64_t *groupids)
4916 {
4917 	DB_RESULT		result;
4918 	DB_ROW			row;
4919 	char			*sql = NULL;
4920 	size_t			sql_alloc = 0, sql_offset = 0;
4921 	zbx_vector_uint64_t	hostids;
4922 	zbx_uint64_t		groupid;
4923 	int			index, internal;
4924 
4925 	if (0 == groupids->values_num)
4926 		return;
4927 
4928 	zbx_vector_uint64_create(&hostids);
4929 
4930 	/* select of the list of hosts which remain without groups */
4931 
4932 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
4933 			"select hg.hostid"
4934 			" from hosts_groups hg"
4935 			" where");
4936 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hg.groupid", groupids->values, groupids->values_num);
4937 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
4938 			" and not exists ("
4939 				"select null"
4940 				" from hosts_groups hg2"
4941 				" where hg.hostid=hg2.hostid"
4942 					" and not");
4943 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hg2.groupid", groupids->values, groupids->values_num);
4944 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
4945 			")");
4946 
4947 	DBselect_uint64(sql, &hostids);
4948 
4949 	/* select of the list of groups which cannot be deleted */
4950 
4951 	sql_offset = 0;
4952 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
4953 			"select g.groupid,g.internal,g.name"
4954 			" from groups g"
4955 			" where");
4956 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "g.groupid", groupids->values, groupids->values_num);
4957 	if (0 < hostids.values_num)
4958 	{
4959 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
4960 				" and (g.internal=%d"
4961 					" or exists ("
4962 						"select null"
4963 						" from hosts_groups hg"
4964 						" where g.groupid=hg.groupid"
4965 							" and",
4966 				ZBX_INTERNAL_GROUP);
4967 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hg.hostid", hostids.values, hostids.values_num);
4968 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "))");
4969 	}
4970 	else
4971 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and g.internal=%d", ZBX_INTERNAL_GROUP);
4972 
4973 	result = DBselect("%s", sql);
4974 
4975 	while (NULL != (row = DBfetch(result)))
4976 	{
4977 		ZBX_STR2UINT64(groupid, row[0]);
4978 		internal = atoi(row[1]);
4979 
4980 		if (FAIL != (index = zbx_vector_uint64_bsearch(groupids, groupid, ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
4981 			zbx_vector_uint64_remove(groupids, index);
4982 
4983 		if (ZBX_INTERNAL_GROUP == internal)
4984 		{
4985 			zabbix_log(LOG_LEVEL_WARNING, "host group \"%s\" is internal and cannot be deleted", row[2]);
4986 		}
4987 		else
4988 		{
4989 			zabbix_log(LOG_LEVEL_WARNING, "host group \"%s\" cannot be deleted,"
4990 					" because some hosts or templates depend on it", row[2]);
4991 		}
4992 	}
4993 	DBfree_result(result);
4994 
4995 	/* check if groups is used in the groups prototypes */
4996 
4997 	if (0 != groupids->values_num)
4998 	{
4999 		sql_offset = 0;
5000 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
5001 				"select g.groupid,g.name"
5002 				" from groups g"
5003 				" where");
5004 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "g.groupid",
5005 				groupids->values, groupids->values_num);
5006 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
5007 					" and exists ("
5008 						"select null"
5009 						" from group_prototype gp"
5010 						" where g.groupid=gp.groupid"
5011 					")");
5012 
5013 		result = DBselect("%s", sql);
5014 
5015 		while (NULL != (row = DBfetch(result)))
5016 		{
5017 			ZBX_STR2UINT64(groupid, row[0]);
5018 
5019 			if (FAIL != (index = zbx_vector_uint64_bsearch(groupids, groupid,
5020 					ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
5021 			{
5022 				zbx_vector_uint64_remove(groupids, index);
5023 			}
5024 
5025 			zabbix_log(LOG_LEVEL_WARNING, "host group \"%s\" cannot be deleted,"
5026 					" because it is used by a host prototype", row[1]);
5027 		}
5028 		DBfree_result(result);
5029 	}
5030 
5031 	zbx_vector_uint64_destroy(&hostids);
5032 	zbx_free(sql);
5033 }
5034 
5035 /******************************************************************************
5036  *                                                                            *
5037  * Function: DBdelete_groups                                                  *
5038  *                                                                            *
5039  * Purpose: delete host groups from database                                  *
5040  *                                                                            *
5041  * Parameters: groupids - [IN] array of group identificators from database    *
5042  *                                                                            *
5043  ******************************************************************************/
DBdelete_groups(zbx_vector_uint64_t * groupids)5044 void	DBdelete_groups(zbx_vector_uint64_t *groupids)
5045 {
5046 	const char		*__function_name = "DBdelete_groups";
5047 
5048 	char			*sql = NULL;
5049 	size_t			sql_alloc = 256, sql_offset = 0;
5050 	int			i;
5051 	zbx_vector_uint64_t	profileids, screen_itemids, selementids;
5052 	zbx_uint64_t		resource_types_delete[] = {SCREEN_RESOURCE_DATA_OVERVIEW,
5053 						SCREEN_RESOURCE_TRIGGERS_OVERVIEW};
5054 	zbx_uint64_t		resource_types_update[] = {SCREEN_RESOURCE_HOSTS_INFO, SCREEN_RESOURCE_TRIGGERS_INFO,
5055 						SCREEN_RESOURCE_HOSTGROUP_TRIGGERS, SCREEN_RESOURCE_HOST_TRIGGERS};
5056 	const char		*profile_idxs[] = {"web.dashconf.groups.groupids", "web.dashconf.groups.hide.groupids"};
5057 
5058 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __function_name, groupids->values_num);
5059 
5060 	DBdelete_groups_validate(groupids);
5061 
5062 	if (0 == groupids->values_num)
5063 		goto out;
5064 
5065 	for (i = 0; i < groupids->values_num; i++)
5066 		DBdelete_action_conditions(CONDITION_TYPE_HOST_GROUP, groupids->values[i]);
5067 
5068 	sql = zbx_malloc(sql, sql_alloc);
5069 
5070 	zbx_vector_uint64_create(&profileids);
5071 	zbx_vector_uint64_create(&screen_itemids);
5072 	zbx_vector_uint64_create(&selementids);
5073 
5074 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
5075 
5076 	/* delete sysmaps_elements */
5077 	DBget_sysmapelements_by_element_type_ids(&selementids, SYSMAP_ELEMENT_TYPE_HOST_GROUP, groupids);
5078 	if (0 != selementids.values_num)
5079 	{
5080 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from sysmaps_elements where");
5081 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "selementid", selementids.values,
5082 				selementids.values_num);
5083 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
5084 	}
5085 
5086 	/* delete screens_items (host group is mandatory for this elements) */
5087 	DBget_screenitems_by_resource_types_ids(&screen_itemids, resource_types_delete, ARRSIZE(resource_types_delete),
5088 			groupids);
5089 	if (0 != screen_itemids.values_num)
5090 	{
5091 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from screens_items where");
5092 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "screenitemid", screen_itemids.values,
5093 				screen_itemids.values_num);
5094 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
5095 	}
5096 
5097 	/* update screens_items (host group isn't mandatory for this elements) */
5098 	zbx_vector_uint64_clear(&screen_itemids);
5099 	DBget_screenitems_by_resource_types_ids(&screen_itemids, resource_types_update, ARRSIZE(resource_types_update),
5100 			groupids);
5101 
5102 	if (0 != screen_itemids.values_num)
5103 	{
5104 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update screens_items set resourceid=0 where");
5105 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "screenitemid", screen_itemids.values,
5106 				screen_itemids.values_num);
5107 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
5108 	}
5109 
5110 	DBget_profiles_by_source_idxs_values(&profileids, NULL, profile_idxs, ARRSIZE(profile_idxs), groupids);
5111 	if (0 != profileids.values_num)
5112 	{
5113 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from profiles where");
5114 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "profileid", profileids.values,
5115 				profileids.values_num);
5116 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
5117 	}
5118 
5119 	/* groups */
5120 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from groups where");
5121 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid", groupids->values, groupids->values_num);
5122 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
5123 
5124 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
5125 
5126 	DBexecute("%s", sql);
5127 
5128 	zbx_vector_uint64_destroy(&selementids);
5129 	zbx_vector_uint64_destroy(&screen_itemids);
5130 	zbx_vector_uint64_destroy(&profileids);
5131 
5132 	zbx_free(sql);
5133 out:
5134 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
5135 }
5136 
5137 /******************************************************************************
5138  *                                                                            *
5139  * Function: DBadd_host_inventory                                             *
5140  *                                                                            *
5141  * Purpose: adds host inventory to the host                                   *
5142  *                                                                            *
5143  * Parameters: hostid         - [IN] host identifier                          *
5144  *             inventory_mode - [IN] the host inventory mode                  *
5145  *                                                                            *
5146  ******************************************************************************/
DBadd_host_inventory(zbx_uint64_t hostid,int inventory_mode)5147 void	DBadd_host_inventory(zbx_uint64_t hostid, int inventory_mode)
5148 {
5149 	zbx_db_insert_t	db_insert;
5150 
5151 	zbx_db_insert_prepare(&db_insert, "host_inventory", "hostid", "inventory_mode", NULL);
5152 	zbx_db_insert_add_values(&db_insert, hostid, inventory_mode);
5153 	zbx_db_insert_execute(&db_insert);
5154 	zbx_db_insert_clean(&db_insert);
5155 }
5156 
5157 /******************************************************************************
5158  *                                                                            *
5159  * Function: DBset_host_inventory                                             *
5160  *                                                                            *
5161  * Purpose: sets host inventory mode for the specified host                   *
5162  *                                                                            *
5163  * Parameters: hostid         - [IN] host identifier                          *
5164  *             inventory_mode - [IN] the host inventory mode                  *
5165  *                                                                            *
5166  * Comments: The host_inventory table record is created if absent.            *
5167  *                                                                            *
5168  *           This function does not allow disabling host inventory - only     *
5169  *           setting manual or automatic host inventory mode is supported.    *
5170  *                                                                            *
5171  ******************************************************************************/
DBset_host_inventory(zbx_uint64_t hostid,int inventory_mode)5172 void	DBset_host_inventory(zbx_uint64_t hostid, int inventory_mode)
5173 {
5174 	DB_RESULT	result;
5175 	DB_ROW		row;
5176 
5177 	result = DBselect("select inventory_mode from host_inventory where hostid=" ZBX_FS_UI64, hostid);
5178 
5179 	if (NULL == (row = DBfetch(result)))
5180 	{
5181 		DBadd_host_inventory(hostid, inventory_mode);
5182 	}
5183 	else if (inventory_mode != atoi(row[0]))
5184 	{
5185 		DBexecute("update host_inventory set inventory_mode=%d where hostid=" ZBX_FS_UI64, inventory_mode,
5186 				hostid);
5187 	}
5188 
5189 	DBfree_result(result);
5190 }
5191