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