1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "lld.h"
21 #include "db.h"
22 #include "log.h"
23 #include "zbxalgo.h"
24 #include "zbxserver.h"
25 
26 typedef struct
27 {
28 	zbx_uint64_t		triggerid;
29 	char			*description;
30 	char			*expression;
31 	char			*recovery_expression;
32 	char			*comments;
33 	char			*url;
34 	char			*correlation_tag;
35 	char			*opdata;
36 	unsigned char		status;
37 	unsigned char		type;
38 	unsigned char		priority;
39 	unsigned char		recovery_mode;
40 	unsigned char		correlation_mode;
41 	unsigned char		manual_close;
42 	unsigned char		discover;
43 	zbx_vector_ptr_t	functions;
44 	zbx_vector_ptr_t	dependencies;
45 	zbx_vector_ptr_t	tags;
46 }
47 zbx_lld_trigger_prototype_t;
48 
49 typedef struct
50 {
51 	zbx_uint64_t		triggerid;
52 	zbx_uint64_t		parent_triggerid;
53 	char			*description;
54 	char			*description_orig;
55 	char			*expression;
56 	char			*expression_orig;
57 	char			*recovery_expression;
58 	char			*recovery_expression_orig;
59 	char			*comments;
60 	char			*comments_orig;
61 	char			*url;
62 	char			*url_orig;
63 	char			*correlation_tag;
64 	char			*correlation_tag_orig;
65 	char			*opdata;
66 	char			*opdata_orig;
67 	zbx_vector_ptr_t	functions;
68 	zbx_vector_ptr_t	dependencies;
69 	zbx_vector_ptr_t	dependents;
70 	zbx_vector_ptr_t	tags;
71 	zbx_vector_ptr_pair_t	override_tags;
72 #define ZBX_FLAG_LLD_TRIGGER_UNSET			__UINT64_C(0x0000)
73 #define ZBX_FLAG_LLD_TRIGGER_DISCOVERED			__UINT64_C(0x0001)
74 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION		__UINT64_C(0x0002)
75 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION		__UINT64_C(0x0004)
76 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE		__UINT64_C(0x0008)
77 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY		__UINT64_C(0x0010)
78 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS		__UINT64_C(0x0020)
79 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_URL			__UINT64_C(0x0040)
80 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION	__UINT64_C(0x0080)
81 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_MODE	__UINT64_C(0x0100)
82 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_MODE	__UINT64_C(0x0200)
83 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_TAG	__UINT64_C(0x0400)
84 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_MANUAL_CLOSE	__UINT64_C(0x0800)
85 #define ZBX_FLAG_LLD_TRIGGER_UPDATE_OPDATA		__UINT64_C(0x1000)
86 #define ZBX_FLAG_LLD_TRIGGER_UPDATE										\
87 		(ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION | ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION |		\
88 		ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE | ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY |			\
89 		ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS | ZBX_FLAG_LLD_TRIGGER_UPDATE_URL |			\
90 		ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION | ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_MODE |	\
91 		ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_MODE | ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_TAG |	\
92 		ZBX_FLAG_LLD_TRIGGER_UPDATE_MANUAL_CLOSE | ZBX_FLAG_LLD_TRIGGER_UPDATE_OPDATA)
93 	zbx_uint64_t		flags;
94 	int			lastcheck;
95 	int			ts_delete;
96 	unsigned char		status;
97 	unsigned char		priority;
98 }
99 zbx_lld_trigger_t;
100 
101 typedef struct
102 {
103 	zbx_uint64_t	functionid;
104 	zbx_uint64_t	index;
105 	zbx_uint64_t	itemid;
106 	zbx_uint64_t	itemid_orig;
107 	char		*function;
108 	char		*function_orig;
109 	char		*parameter;
110 	char		*parameter_orig;
111 #define ZBX_FLAG_LLD_FUNCTION_UNSET			__UINT64_C(0x00)
112 #define ZBX_FLAG_LLD_FUNCTION_DISCOVERED		__UINT64_C(0x01)
113 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID		__UINT64_C(0x02)
114 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION		__UINT64_C(0x04)
115 #define ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER		__UINT64_C(0x08)
116 #define ZBX_FLAG_LLD_FUNCTION_UPDATE								\
117 		(ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID | ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION |	\
118 		ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER)
119 #define ZBX_FLAG_LLD_FUNCTION_DELETE			__UINT64_C(0x10)
120 	zbx_uint64_t	flags;
121 }
122 zbx_lld_function_t;
123 
124 typedef struct
125 {
126 	zbx_uint64_t		triggerdepid;
127 	zbx_uint64_t		triggerid_up;	/* generic trigger */
128 	zbx_lld_trigger_t	*trigger_up;	/* lld-created trigger; (null) if trigger depends on generic trigger */
129 #define ZBX_FLAG_LLD_DEPENDENCY_UNSET			__UINT64_C(0x00)
130 #define ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED		__UINT64_C(0x01)
131 #define ZBX_FLAG_LLD_DEPENDENCY_DELETE			__UINT64_C(0x02)
132 	zbx_uint64_t		flags;
133 }
134 zbx_lld_dependency_t;
135 
136 typedef struct
137 {
138 	zbx_uint64_t	triggertagid;
139 	char		*tag;
140 	char		*value;
141 #define ZBX_FLAG_LLD_TAG_UNSET				__UINT64_C(0x00)
142 #define ZBX_FLAG_LLD_TAG_DISCOVERED			__UINT64_C(0x01)
143 #define ZBX_FLAG_LLD_TAG_UPDATE_TAG			__UINT64_C(0x02)
144 #define ZBX_FLAG_LLD_TAG_UPDATE_VALUE			__UINT64_C(0x04)
145 #define ZBX_FLAG_LLD_TAG_UPDATE							\
146 		(ZBX_FLAG_LLD_TAG_UPDATE_TAG | ZBX_FLAG_LLD_TAG_UPDATE_VALUE)
147 #define ZBX_FLAG_LLD_TAG_DELETE				__UINT64_C(0x08)
148 	zbx_uint64_t	flags;
149 }
150 zbx_lld_tag_t;
151 
152 typedef struct
153 {
154 	zbx_uint64_t		parent_triggerid;
155 	zbx_uint64_t		itemid;
156 	zbx_lld_trigger_t	*trigger;
157 }
158 zbx_lld_item_trigger_t;
159 
160 typedef struct
161 {
162 	zbx_uint64_t	itemid;
163 	unsigned char	flags;
164 }
165 zbx_lld_item_t;
166 
167 /* a reference to trigger which could be either existing trigger in database or */
168 /* a just discovered trigger stored in memory                                   */
169 typedef struct
170 {
171 	/* trigger id, 0 for newly discovered triggers */
172 	zbx_uint64_t		triggerid;
173 
174 	/* trigger data, NULL for non-discovered triggers */
175 	zbx_lld_trigger_t	*trigger;
176 
177 	/* flags to mark trigger dependencies during trigger dependency validation */
178 #define ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL	0
179 #define ZBX_LLD_TRIGGER_DEPENDENCY_NEW		1
180 #define ZBX_LLD_TRIGGER_DEPENDENCY_DELETE	2
181 
182 	/* flags used to mark dependencies when trigger reference is use to store dependency links */
183 	int			flags;
184 }
185 zbx_lld_trigger_ref_t;
186 
187 /* a trigger node used to build trigger tree for dependency validation */
188 typedef struct
189 {
190 	/* trigger reference */
191 	zbx_lld_trigger_ref_t	trigger_ref;
192 
193 	/* the current iteration number, used during dependency validation */
194 	int			iter_num;
195 
196 	/* the number of dependents */
197 	int			parents;
198 
199 	/* trigger dependency list */
200 	zbx_vector_ptr_t	dependencies;
201 }
202 zbx_lld_trigger_node_t;
203 
204 /* a structure to keep information about current iteration during trigger dependencies validation */
205 typedef struct
206 {
207 	/* iteration number */
208 	int			iter_num;
209 
210 	/* the dependency (from->to) that should be removed in the case of recursive loop */
211 	zbx_lld_trigger_ref_t	*ref_from;
212 	zbx_lld_trigger_ref_t	*ref_to;
213 }
214 zbx_lld_trigger_node_iter_t;
215 
216 
lld_tag_free(zbx_lld_tag_t * tag)217 static void	lld_tag_free(zbx_lld_tag_t *tag)
218 {
219 	zbx_free(tag->tag);
220 	zbx_free(tag->value);
221 	zbx_free(tag);
222 }
223 
lld_item_free(zbx_lld_item_t * item)224 static void	lld_item_free(zbx_lld_item_t *item)
225 {
226 	zbx_free(item);
227 }
228 
lld_function_free(zbx_lld_function_t * function)229 static void	lld_function_free(zbx_lld_function_t *function)
230 {
231 	zbx_free(function->parameter_orig);
232 	zbx_free(function->parameter);
233 	zbx_free(function->function_orig);
234 	zbx_free(function->function);
235 	zbx_free(function);
236 }
237 
lld_trigger_prototype_free(zbx_lld_trigger_prototype_t * trigger_prototype)238 static void	lld_trigger_prototype_free(zbx_lld_trigger_prototype_t *trigger_prototype)
239 {
240 	zbx_vector_ptr_clear_ext(&trigger_prototype->tags, (zbx_clean_func_t)lld_tag_free);
241 	zbx_vector_ptr_destroy(&trigger_prototype->tags);
242 	zbx_vector_ptr_clear_ext(&trigger_prototype->dependencies, zbx_ptr_free);
243 	zbx_vector_ptr_destroy(&trigger_prototype->dependencies);
244 	zbx_vector_ptr_clear_ext(&trigger_prototype->functions, (zbx_mem_free_func_t)lld_function_free);
245 	zbx_vector_ptr_destroy(&trigger_prototype->functions);
246 	zbx_free(trigger_prototype->opdata);
247 	zbx_free(trigger_prototype->correlation_tag);
248 	zbx_free(trigger_prototype->url);
249 	zbx_free(trigger_prototype->comments);
250 	zbx_free(trigger_prototype->recovery_expression);
251 	zbx_free(trigger_prototype->expression);
252 	zbx_free(trigger_prototype->description);
253 	zbx_free(trigger_prototype);
254 }
255 
lld_trigger_free(zbx_lld_trigger_t * trigger)256 static void	lld_trigger_free(zbx_lld_trigger_t *trigger)
257 {
258 	zbx_vector_ptr_clear_ext(&trigger->tags, (zbx_clean_func_t)lld_tag_free);
259 	zbx_vector_ptr_pair_destroy(&trigger->override_tags);
260 	zbx_vector_ptr_destroy(&trigger->tags);
261 	zbx_vector_ptr_destroy(&trigger->dependents);
262 	zbx_vector_ptr_clear_ext(&trigger->dependencies, zbx_ptr_free);
263 	zbx_vector_ptr_destroy(&trigger->dependencies);
264 	zbx_vector_ptr_clear_ext(&trigger->functions, (zbx_clean_func_t)lld_function_free);
265 	zbx_vector_ptr_destroy(&trigger->functions);
266 	zbx_free(trigger->opdata_orig);
267 	zbx_free(trigger->opdata);
268 	zbx_free(trigger->correlation_tag_orig);
269 	zbx_free(trigger->correlation_tag);
270 	zbx_free(trigger->url_orig);
271 	zbx_free(trigger->url);
272 	zbx_free(trigger->comments_orig);
273 	zbx_free(trigger->comments);
274 	zbx_free(trigger->recovery_expression_orig);
275 	zbx_free(trigger->recovery_expression);
276 	zbx_free(trigger->expression_orig);
277 	zbx_free(trigger->expression);
278 	zbx_free(trigger->description_orig);
279 	zbx_free(trigger->description);
280 	zbx_free(trigger);
281 }
282 
283 /******************************************************************************
284  *                                                                            *
285  * Function: lld_trigger_prototypes_get                                       *
286  *                                                                            *
287  * Purpose: retrieve trigger prototypes which are inherited from the          *
288  *          discovery rule                                                    *
289  *                                                                            *
290  * Parameters: lld_ruleid         - [IN] discovery rule id                    *
291  *             trigger_prototypes - [OUT] sorted list of trigger prototypes   *
292  *                                                                            *
293  ******************************************************************************/
lld_trigger_prototypes_get(zbx_uint64_t lld_ruleid,zbx_vector_ptr_t * trigger_prototypes)294 static void	lld_trigger_prototypes_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *trigger_prototypes)
295 {
296 	DB_RESULT			result;
297 	DB_ROW				row;
298 	zbx_lld_trigger_prototype_t	*trigger_prototype;
299 
300 	result = DBselect(
301 			"select distinct t.triggerid,t.description,t.expression,t.status,t.type,t.priority,t.comments,"
302 				"t.url,t.recovery_expression,t.recovery_mode,t.correlation_mode,t.correlation_tag,"
303 				"t.manual_close,t.opdata,t.discover"
304 			" from triggers t,functions f,items i,item_discovery id"
305 			" where t.triggerid=f.triggerid"
306 				" and f.itemid=i.itemid"
307 				" and i.itemid=id.itemid"
308 				" and id.parent_itemid=" ZBX_FS_UI64,
309 			lld_ruleid);
310 
311 	/* run through trigger prototypes */
312 	while (NULL != (row = DBfetch(result)))
313 	{
314 		trigger_prototype = (zbx_lld_trigger_prototype_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_prototype_t));
315 
316 		ZBX_STR2UINT64(trigger_prototype->triggerid, row[0]);
317 		trigger_prototype->description = zbx_strdup(NULL, row[1]);
318 		trigger_prototype->expression = zbx_strdup(NULL, row[2]);
319 		trigger_prototype->recovery_expression = zbx_strdup(NULL, row[8]);
320 		ZBX_STR2UCHAR(trigger_prototype->status, row[3]);
321 		ZBX_STR2UCHAR(trigger_prototype->type, row[4]);
322 		ZBX_STR2UCHAR(trigger_prototype->priority, row[5]);
323 		ZBX_STR2UCHAR(trigger_prototype->recovery_mode, row[9]);
324 		trigger_prototype->comments = zbx_strdup(NULL, row[6]);
325 		trigger_prototype->url = zbx_strdup(NULL, row[7]);
326 		ZBX_STR2UCHAR(trigger_prototype->correlation_mode, row[10]);
327 		trigger_prototype->correlation_tag = zbx_strdup(NULL, row[11]);
328 		ZBX_STR2UCHAR(trigger_prototype->manual_close, row[12]);
329 		trigger_prototype->opdata = zbx_strdup(NULL, row[13]);
330 		ZBX_STR2UCHAR(trigger_prototype->discover, row[14]);
331 
332 		zbx_vector_ptr_create(&trigger_prototype->functions);
333 		zbx_vector_ptr_create(&trigger_prototype->dependencies);
334 		zbx_vector_ptr_create(&trigger_prototype->tags);
335 
336 		zbx_vector_ptr_append(trigger_prototypes, trigger_prototype);
337 	}
338 	DBfree_result(result);
339 
340 	zbx_vector_ptr_sort(trigger_prototypes, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
341 }
342 
343 /******************************************************************************
344  *                                                                            *
345  * Function: lld_triggers_get                                                 *
346  *                                                                            *
347  * Purpose: retrieve triggers which were created by the specified trigger     *
348  *          prototypes                                                        *
349  *                                                                            *
350  * Parameters: trigger_prototypes - [IN] sorted list of trigger prototypes    *
351  *             triggers           - [OUT] sorted list of triggers             *
352  *                                                                            *
353  ******************************************************************************/
lld_triggers_get(const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)354 static void	lld_triggers_get(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
355 {
356 	DB_RESULT		result;
357 	DB_ROW			row;
358 	zbx_vector_uint64_t	parent_triggerids;
359 	char			*sql = NULL;
360 	size_t			sql_alloc = 256, sql_offset = 0;
361 	int			i;
362 
363 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
364 
365 	zbx_vector_uint64_create(&parent_triggerids);
366 	zbx_vector_uint64_reserve(&parent_triggerids, trigger_prototypes->values_num);
367 
368 	for (i = 0; i < trigger_prototypes->values_num; i++)
369 	{
370 		const zbx_lld_trigger_prototype_t	*trigger_prototype;
371 
372 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
373 
374 		zbx_vector_uint64_append(&parent_triggerids, trigger_prototype->triggerid);
375 	}
376 
377 	sql = (char *)zbx_malloc(sql, sql_alloc);
378 
379 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
380 			"select td.parent_triggerid,t.triggerid,t.description,t.expression,t.type,t.priority,"
381 				"t.comments,t.url,t.recovery_expression,t.recovery_mode,t.correlation_mode,"
382 				"t.correlation_tag,t.manual_close,t.opdata,td.lastcheck,td.ts_delete"
383 			" from triggers t,trigger_discovery td"
384 			" where t.triggerid=td.triggerid"
385 				" and");
386 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.parent_triggerid",
387 			parent_triggerids.values, parent_triggerids.values_num);
388 
389 	zbx_vector_uint64_destroy(&parent_triggerids);
390 
391 	result = DBselect("%s", sql);
392 
393 	zbx_free(sql);
394 
395 	while (NULL != (row = DBfetch(result)))
396 	{
397 		zbx_uint64_t				parent_triggerid;
398 		const zbx_lld_trigger_prototype_t	*trigger_prototype;
399 		zbx_lld_trigger_t			*trigger;
400 		int					index;
401 
402 		ZBX_STR2UINT64(parent_triggerid, row[0]);
403 
404 		if (FAIL == (index = zbx_vector_ptr_bsearch(trigger_prototypes, &parent_triggerid,
405 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
406 		{
407 			THIS_SHOULD_NEVER_HAPPEN;
408 			continue;
409 		}
410 
411 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
412 
413 		trigger = (zbx_lld_trigger_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
414 
415 		ZBX_STR2UINT64(trigger->triggerid, row[1]);
416 		trigger->parent_triggerid = parent_triggerid;
417 		trigger->description = zbx_strdup(NULL, row[2]);
418 		trigger->description_orig = NULL;
419 		trigger->expression = zbx_strdup(NULL, row[3]);
420 		trigger->expression_orig = NULL;
421 		trigger->recovery_expression = zbx_strdup(NULL, row[8]);
422 		trigger->recovery_expression_orig = NULL;
423 
424 		trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
425 
426 		if ((unsigned char)atoi(row[4]) != trigger_prototype->type)
427 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE;
428 
429 		trigger->priority = (unsigned char)atoi(row[5]);
430 
431 		if ((unsigned char)atoi(row[9]) != trigger_prototype->recovery_mode)
432 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_MODE;
433 
434 		if ((unsigned char)atoi(row[10]) != trigger_prototype->correlation_mode)
435 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_MODE;
436 
437 		if ((unsigned char)atoi(row[12]) != trigger_prototype->manual_close)
438 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_MANUAL_CLOSE;
439 
440 		trigger->comments = zbx_strdup(NULL, row[6]);
441 		trigger->comments_orig = NULL;
442 		trigger->url = zbx_strdup(NULL, row[7]);
443 		trigger->url_orig = NULL;
444 		trigger->correlation_tag = zbx_strdup(NULL, row[11]);
445 		trigger->correlation_tag_orig = NULL;
446 		trigger->opdata = zbx_strdup(NULL, row[13]);
447 		trigger->opdata_orig = NULL;
448 		trigger->lastcheck = atoi(row[14]);
449 		trigger->ts_delete = atoi(row[15]);
450 
451 		zbx_vector_ptr_create(&trigger->functions);
452 		zbx_vector_ptr_create(&trigger->dependencies);
453 		zbx_vector_ptr_create(&trigger->dependents);
454 		zbx_vector_ptr_create(&trigger->tags);
455 		zbx_vector_ptr_pair_create(&trigger->override_tags);
456 
457 		zbx_vector_ptr_append(triggers, trigger);
458 	}
459 	DBfree_result(result);
460 
461 	zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
462 
463 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
464 }
465 
466 /******************************************************************************
467  *                                                                            *
468  * Function: lld_functions_get                                                *
469  *                                                                            *
470  * Purpose: retrieve functions which are used by all triggers in the host of  *
471  *          the trigger prototype                                             *
472  *                                                                            *
473  ******************************************************************************/
lld_functions_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)474 static void	lld_functions_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
475 {
476 	int				i;
477 	zbx_lld_trigger_prototype_t	*trigger_prototype;
478 	zbx_lld_trigger_t		*trigger;
479 	zbx_vector_uint64_t		triggerids;
480 
481 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
482 
483 	zbx_vector_uint64_create(&triggerids);
484 
485 	if (NULL != trigger_prototypes)
486 	{
487 		for (i = 0; i < trigger_prototypes->values_num; i++)
488 		{
489 			trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
490 
491 			zbx_vector_uint64_append(&triggerids, trigger_prototype->triggerid);
492 		}
493 	}
494 
495 	for (i = 0; i < triggers->values_num; i++)
496 	{
497 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
498 
499 		zbx_vector_uint64_append(&triggerids, trigger->triggerid);
500 	}
501 
502 	if (0 != triggerids.values_num)
503 	{
504 		DB_RESULT		result;
505 		DB_ROW			row;
506 		zbx_lld_function_t	*function;
507 		zbx_uint64_t		triggerid;
508 		char			*sql = NULL;
509 		size_t			sql_alloc = 256, sql_offset = 0;
510 		int			index;
511 
512 		zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
513 
514 		sql = (char *)zbx_malloc(sql, sql_alloc);
515 
516 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
517 				"select functionid,triggerid,itemid,name,parameter"
518 				" from functions"
519 				" where");
520 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid",
521 				triggerids.values, triggerids.values_num);
522 
523 		result = DBselect("%s", sql);
524 
525 		zbx_free(sql);
526 
527 		while (NULL != (row = DBfetch(result)))
528 		{
529 			function = (zbx_lld_function_t *)zbx_malloc(NULL, sizeof(zbx_lld_function_t));
530 
531 			function->index = 0;
532 			ZBX_STR2UINT64(function->functionid, row[0]);
533 			ZBX_STR2UINT64(triggerid, row[1]);
534 			ZBX_STR2UINT64(function->itemid, row[2]);
535 			function->itemid_orig = 0;
536 			function->function = zbx_strdup(NULL, row[3]);
537 			function->function_orig = NULL;
538 			function->parameter = zbx_strdup(NULL, row[4]);
539 			function->parameter_orig = NULL;
540 			function->flags = ZBX_FLAG_LLD_FUNCTION_UNSET;
541 
542 			if (NULL != trigger_prototypes && FAIL != (index = zbx_vector_ptr_bsearch(trigger_prototypes,
543 					&triggerid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
544 			{
545 				trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
546 
547 				zbx_vector_ptr_append(&trigger_prototype->functions, function);
548 			}
549 			else if (FAIL != (index = zbx_vector_ptr_bsearch(triggers, &triggerid,
550 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
551 			{
552 				trigger = (zbx_lld_trigger_t *)triggers->values[index];
553 
554 				zbx_vector_ptr_append(&trigger->functions, function);
555 			}
556 			else
557 			{
558 				THIS_SHOULD_NEVER_HAPPEN;
559 				lld_function_free(function);
560 			}
561 		}
562 		DBfree_result(result);
563 
564 		if (NULL != trigger_prototypes)
565 		{
566 			for (i = 0; i < trigger_prototypes->values_num; i++)
567 			{
568 				trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
569 
570 				zbx_vector_ptr_sort(&trigger_prototype->functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
571 			}
572 		}
573 
574 		for (i = 0; i < triggers->values_num; i++)
575 		{
576 			trigger = (zbx_lld_trigger_t *)triggers->values[i];
577 
578 			zbx_vector_ptr_sort(&trigger->functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
579 		}
580 	}
581 
582 	zbx_vector_uint64_destroy(&triggerids);
583 
584 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
585 }
586 
587 /******************************************************************************
588  *                                                                            *
589  * Function: lld_dependencies_get                                             *
590  *                                                                            *
591  * Purpose: retrieve trigger dependencies                                     *
592  *                                                                            *
593  ******************************************************************************/
lld_dependencies_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)594 static void	lld_dependencies_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
595 {
596 	DB_RESULT			result;
597 	DB_ROW				row;
598 	zbx_lld_trigger_prototype_t	*trigger_prototype;
599 	zbx_lld_trigger_t		*trigger;
600 	zbx_lld_dependency_t		*dependency;
601 	zbx_vector_uint64_t		triggerids;
602 	zbx_uint64_t			triggerid_down;
603 	char				*sql = NULL;
604 	size_t				sql_alloc = 256, sql_offset = 0;
605 	int				i, index;
606 
607 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
608 
609 	zbx_vector_uint64_create(&triggerids);
610 
611 	for (i = 0; i < trigger_prototypes->values_num; i++)
612 	{
613 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
614 
615 		zbx_vector_uint64_append(&triggerids, trigger_prototype->triggerid);
616 	}
617 
618 	for (i = 0; i < triggers->values_num; i++)
619 	{
620 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
621 
622 		zbx_vector_uint64_append(&triggerids, trigger->triggerid);
623 	}
624 
625 	zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
626 
627 	sql = (char *)zbx_malloc(sql, sql_alloc);
628 
629 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
630 			"select triggerdepid,triggerid_down,triggerid_up"
631 			" from trigger_depends"
632 			" where");
633 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid_down",
634 			triggerids.values, triggerids.values_num);
635 
636 	zbx_vector_uint64_destroy(&triggerids);
637 
638 	result = DBselect("%s", sql);
639 
640 	zbx_free(sql);
641 
642 	while (NULL != (row = DBfetch(result)))
643 	{
644 		dependency = (zbx_lld_dependency_t *)zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
645 
646 		ZBX_STR2UINT64(dependency->triggerdepid, row[0]);
647 		ZBX_STR2UINT64(triggerid_down, row[1]);
648 		ZBX_STR2UINT64(dependency->triggerid_up, row[2]);
649 		dependency->trigger_up = NULL;
650 		dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_UNSET;
651 
652 		if (FAIL != (index = zbx_vector_ptr_bsearch(trigger_prototypes, &triggerid_down,
653 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
654 		{
655 			trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
656 
657 			zbx_vector_ptr_append(&trigger_prototype->dependencies, dependency);
658 		}
659 		else if (FAIL != (index = zbx_vector_ptr_bsearch(triggers, &triggerid_down,
660 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
661 		{
662 			trigger = (zbx_lld_trigger_t *)triggers->values[index];
663 
664 			zbx_vector_ptr_append(&trigger->dependencies, dependency);
665 		}
666 		else
667 		{
668 			THIS_SHOULD_NEVER_HAPPEN;
669 			zbx_ptr_free(dependency);
670 		}
671 	}
672 	DBfree_result(result);
673 
674 	for (i = 0; i < trigger_prototypes->values_num; i++)
675 	{
676 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
677 
678 		zbx_vector_ptr_sort(&trigger_prototype->dependencies, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
679 	}
680 
681 	for (i = 0; i < triggers->values_num; i++)
682 	{
683 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
684 
685 		zbx_vector_ptr_sort(&trigger->dependencies, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
686 	}
687 
688 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
689 }
690 
691 /******************************************************************************
692  *                                                                            *
693  * Function: lld_tags_get                                                     *
694  *                                                                            *
695  * Purpose: retrieve trigger tags                                             *
696  *                                                                            *
697  ******************************************************************************/
lld_tags_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers)698 static void	lld_tags_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers)
699 {
700 	DB_RESULT			result;
701 	DB_ROW				row;
702 	zbx_vector_uint64_t		triggerids;
703 	int				i, index;
704 	zbx_lld_trigger_prototype_t	*trigger_prototype;
705 	zbx_lld_trigger_t		*trigger;
706 	zbx_lld_tag_t			*tag;
707 	char				*sql = NULL;
708 	size_t				sql_alloc = 256, sql_offset = 0;
709 	zbx_uint64_t			triggerid;
710 
711 	zbx_vector_uint64_create(&triggerids);
712 
713 	for (i = 0; i < trigger_prototypes->values_num; i++)
714 	{
715 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
716 
717 		zbx_vector_uint64_append(&triggerids, trigger_prototype->triggerid);
718 	}
719 
720 	for (i = 0; i < triggers->values_num; i++)
721 	{
722 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
723 
724 		zbx_vector_uint64_append(&triggerids, trigger->triggerid);
725 	}
726 
727 	zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
728 
729 	sql = (char *)zbx_malloc(sql, sql_alloc);
730 
731 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
732 			"select triggertagid,triggerid,tag,value"
733 			" from trigger_tag"
734 			" where");
735 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerid",
736 			triggerids.values, triggerids.values_num);
737 
738 	zbx_vector_uint64_destroy(&triggerids);
739 
740 	result = DBselect("%s", sql);
741 
742 	zbx_free(sql);
743 
744 	while (NULL != (row = DBfetch(result)))
745 	{
746 		tag = (zbx_lld_tag_t *)zbx_malloc(NULL, sizeof(zbx_lld_tag_t));
747 
748 		ZBX_STR2UINT64(tag->triggertagid, row[0]);
749 		ZBX_STR2UINT64(triggerid, row[1]);
750 		tag->tag = zbx_strdup(NULL, row[2]);
751 		tag->value = zbx_strdup(NULL, row[3]);
752 		tag->flags = ZBX_FLAG_LLD_DEPENDENCY_UNSET;
753 
754 		if (FAIL != (index = zbx_vector_ptr_bsearch(trigger_prototypes, &triggerid,
755 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
756 		{
757 			trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
758 
759 			zbx_vector_ptr_append(&trigger_prototype->tags, tag);
760 		}
761 		else if (FAIL != (index = zbx_vector_ptr_bsearch(triggers, &triggerid,
762 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
763 		{
764 			trigger = (zbx_lld_trigger_t *)triggers->values[index];
765 
766 			zbx_vector_ptr_append(&trigger->tags, tag);
767 		}
768 		else
769 		{
770 			THIS_SHOULD_NEVER_HAPPEN;
771 			zbx_ptr_free(tag);
772 		}
773 
774 	}
775 	DBfree_result(result);
776 
777 	for (i = 0; i < trigger_prototypes->values_num; i++)
778 	{
779 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
780 
781 		zbx_vector_ptr_sort(&trigger_prototype->tags, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
782 	}
783 
784 	for (i = 0; i < triggers->values_num; i++)
785 	{
786 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
787 
788 		zbx_vector_ptr_sort(&trigger->tags, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
789 	}
790 
791 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
792 }
793 
794 /******************************************************************************
795  *                                                                            *
796  * Function: lld_items_get                                                    *
797  *                                                                            *
798  * Purpose: returns the list of items which are related to the trigger        *
799  *          prototypes                                                        *
800  *                                                                            *
801  * Parameters: trigger_prototypes - [IN] a vector of trigger prototypes       *
802  *             items              - [OUT] sorted list of items                *
803  *                                                                            *
804  ******************************************************************************/
lld_items_get(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * items)805 static void	lld_items_get(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *items)
806 {
807 	DB_RESULT		result;
808 	DB_ROW			row;
809 	zbx_lld_item_t		*item;
810 	zbx_vector_uint64_t	parent_triggerids;
811 	char			*sql = NULL;
812 	size_t			sql_alloc = 256, sql_offset = 0;
813 	int			i;
814 
815 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
816 
817 	zbx_vector_uint64_create(&parent_triggerids);
818 	zbx_vector_uint64_reserve(&parent_triggerids, trigger_prototypes->values_num);
819 
820 	for (i = 0; i < trigger_prototypes->values_num; i++)
821 	{
822 		zbx_lld_trigger_prototype_t	*trigger_prototype;
823 
824 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
825 
826 		zbx_vector_uint64_append(&parent_triggerids, trigger_prototype->triggerid);
827 	}
828 	sql = (char *)zbx_malloc(sql, sql_alloc);
829 
830 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
831 			"select distinct i.itemid,i.flags"
832 			" from items i,functions f"
833 			" where i.itemid=f.itemid"
834 				" and");
835 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "f.triggerid",
836 			parent_triggerids.values, parent_triggerids.values_num);
837 
838 	zbx_vector_uint64_destroy(&parent_triggerids);
839 
840 	result = DBselect("%s", sql);
841 
842 	zbx_free(sql);
843 
844 	while (NULL != (row = DBfetch(result)))
845 	{
846 		item = (zbx_lld_item_t *)zbx_malloc(NULL, sizeof(zbx_lld_item_t));
847 
848 		ZBX_STR2UINT64(item->itemid, row[0]);
849 		ZBX_STR2UCHAR(item->flags, row[1]);
850 
851 		zbx_vector_ptr_append(items, item);
852 	}
853 	DBfree_result(result);
854 
855 	zbx_vector_ptr_sort(items, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
856 
857 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
858 }
859 
860 /******************************************************************************
861  *                                                                            *
862  * Function: lld_trigger_get                                                  *
863  *                                                                            *
864  * Purpose: finds already existing trigger, using an item prototype and items *
865  *          already created by it                                             *
866  *                                                                            *
867  * Return value: upon successful completion return pointer to the trigger     *
868  *                                                                            *
869  ******************************************************************************/
lld_trigger_get(zbx_uint64_t parent_triggerid,zbx_hashset_t * items_triggers,const zbx_vector_ptr_t * item_links)870 static zbx_lld_trigger_t	*lld_trigger_get(zbx_uint64_t parent_triggerid, zbx_hashset_t *items_triggers,
871 		const zbx_vector_ptr_t *item_links)
872 {
873 	int	i;
874 
875 	for (i = 0; i < item_links->values_num; i++)
876 	{
877 		zbx_lld_item_trigger_t		*item_trigger, item_trigger_local;
878 		const zbx_lld_item_link_t	*item_link = (zbx_lld_item_link_t *)item_links->values[i];
879 
880 		item_trigger_local.parent_triggerid = parent_triggerid;
881 		item_trigger_local.itemid = item_link->itemid;
882 
883 		if (NULL != (item_trigger = (zbx_lld_item_trigger_t *)zbx_hashset_search(items_triggers, &item_trigger_local)))
884 			return item_trigger->trigger;
885 	}
886 
887 	return NULL;
888 }
889 
lld_expression_simplify(char ** expression,zbx_vector_ptr_t * functions,zbx_uint64_t * function_index)890 static void	lld_expression_simplify(char **expression, zbx_vector_ptr_t *functions, zbx_uint64_t *function_index)
891 {
892 	size_t			l, r;
893 	int			index;
894 	zbx_uint64_t		functionid;
895 	zbx_lld_function_t	*function;
896 	char			buffer[ZBX_MAX_UINT64_LEN];
897 
898 	for (l = 0; '\0' != (*expression)[l]; l++)
899 	{
900 		if ('{' != (*expression)[l])
901 			continue;
902 
903 		if ('$' == (*expression)[l + 1])
904 		{
905 			int	macro_r, context_l, context_r;
906 
907 			if (SUCCEED == zbx_user_macro_parse(*expression + l, &macro_r, &context_l, &context_r, NULL))
908 				l += macro_r;
909 			else
910 				l++;
911 
912 			continue;
913 		}
914 
915 		for (r = l + 1; '\0' != (*expression)[r] && '}' != (*expression)[r]; r++)
916 			;
917 
918 		if ('}' != (*expression)[r])
919 			continue;
920 
921 		/* ... > 0 | {12345} + ... */
922 		/*           l     r       */
923 
924 		if (SUCCEED != is_uint64_n(*expression + l + 1, r - l - 1, &functionid))
925 			continue;
926 
927 		if (FAIL != (index = zbx_vector_ptr_bsearch(functions, &functionid,
928 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
929 		{
930 			function = (zbx_lld_function_t *)functions->values[index];
931 
932 			if (0 == function->index)
933 				function->index = ++(*function_index);
934 
935 			zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_UI64, function->index);
936 
937 			r--;
938 			zbx_replace_string(expression, l + 1, &r, buffer);
939 			r++;
940 		}
941 
942 		l = r;
943 	}
944 }
945 
lld_expressions_simplify(char ** expression,char ** recovery_expression,zbx_vector_ptr_t * functions)946 static void	lld_expressions_simplify(char **expression, char **recovery_expression, zbx_vector_ptr_t *functions)
947 {
948 	zbx_uint64_t	function_index = 0;
949 
950 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s' recovery_expression:'%s'", __func__,
951 			*expression, *recovery_expression);
952 
953 	lld_expression_simplify(expression, functions, &function_index);
954 	lld_expression_simplify(recovery_expression, functions, &function_index);
955 
956 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() expression:'%s' recovery_expression:'%s'", __func__,
957 			*expression, *recovery_expression);
958 }
959 
lld_expression_expand(const char * expression,const zbx_vector_ptr_t * functions)960 static char	*lld_expression_expand(const char *expression, const zbx_vector_ptr_t *functions)
961 {
962 	size_t		l, r;
963 	int		i;
964 	zbx_uint64_t	index;
965 	char		*buffer = NULL;
966 	size_t		buffer_alloc = 64, buffer_offset = 0;
967 
968 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __func__, expression);
969 
970 	buffer = (char *)zbx_malloc(buffer, buffer_alloc);
971 
972 	*buffer = '\0';
973 
974 	for (l = 0; '\0' != expression[l]; l++)
975 	{
976 		zbx_chrcpy_alloc(&buffer, &buffer_alloc, &buffer_offset, expression[l]);
977 
978 		if ('{' != expression[l])
979 			continue;
980 
981 		if ('$' == expression[l + 1])
982 		{
983 			int	macro_r, context_l, context_r;
984 
985 			if (SUCCEED == zbx_user_macro_parse(expression + l, &macro_r, &context_l, &context_r, NULL))
986 				l += macro_r;
987 			else
988 				l++;
989 
990 			continue;
991 		}
992 
993 		for (r = l + 1; '\0' != expression[r] && '}' != expression[r]; r++)
994 			;
995 
996 		if ('}' != expression[r])
997 			continue;
998 
999 		/* ... > 0 | {1} + ... */
1000 		/*           l r       */
1001 
1002 		if (SUCCEED != is_uint64_n(expression + l + 1, r - l - 1, &index))
1003 			continue;
1004 
1005 		for (i = 0; i < functions->values_num; i++)
1006 		{
1007 			const zbx_lld_function_t	*function = (zbx_lld_function_t *)functions->values[i];
1008 
1009 			if (function->index != index)
1010 				continue;
1011 
1012 			zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, ZBX_FS_UI64 ":%s(%s)",
1013 					function->itemid, function->function, function->parameter);
1014 
1015 			break;
1016 		}
1017 
1018 		l = r - 1;
1019 	}
1020 
1021 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():'%s'", __func__, buffer);
1022 
1023 	return buffer;
1024 }
1025 
lld_parameter_make(const char * e,char ** exp,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macros,char ** error)1026 static int	lld_parameter_make(const char *e, char **exp, const struct zbx_json_parse *jp_row,
1027 		const zbx_vector_ptr_t *lld_macros, char **error)
1028 {
1029 	int	ret;
1030 	size_t	exp_alloc = 0, exp_offset = 0;
1031 	size_t	length;
1032 	char	err[64];
1033 
1034 	if (FAIL == zbx_function_validate_parameters(e, &length))
1035 	{
1036 		*error = zbx_dsprintf(*error, "Invalid parameter \"%s\"", e);
1037 		return FAIL;
1038 	}
1039 
1040 	if (FAIL == (ret = substitute_function_lld_param(e, length, 0, exp, &exp_alloc, &exp_offset, jp_row, lld_macros,
1041 			err, sizeof(err))))
1042 	{
1043 		*error = zbx_strdup(*error, err);
1044 	}
1045 
1046 	return ret;
1047 }
1048 
lld_function_make(const zbx_lld_function_t * function_proto,zbx_vector_ptr_t * functions,zbx_uint64_t itemid,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macros,char ** error)1049 static int	lld_function_make(const zbx_lld_function_t *function_proto, zbx_vector_ptr_t *functions,
1050 		zbx_uint64_t itemid, const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macros,
1051 		char **error)
1052 {
1053 	int			i, ret, function_found = 0;
1054 	zbx_lld_function_t	*function = NULL;
1055 	char			*proto_parameter = NULL;
1056 
1057 	for (i = 0; i < functions->values_num; i++)
1058 	{
1059 		function = (zbx_lld_function_t *)functions->values[i];
1060 
1061 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
1062 			continue;
1063 
1064 		if (function->index == function_proto->index)
1065 		{
1066 			function_found = 1;
1067 			break;
1068 		}
1069 	}
1070 
1071 	if (FAIL == (ret = lld_parameter_make(function_proto->parameter, &proto_parameter, jp_row, lld_macros, error)))
1072 		goto clean;
1073 
1074 	if (0 == function_found)
1075 	{
1076 		function = (zbx_lld_function_t *)zbx_malloc(NULL, sizeof(zbx_lld_function_t));
1077 
1078 		function->index = function_proto->index;
1079 		function->functionid = 0;
1080 		function->itemid = itemid;
1081 		function->itemid_orig = 0;
1082 		function->function = zbx_strdup(NULL, function_proto->function);
1083 		function->function_orig = NULL;
1084 		function->parameter = proto_parameter;
1085 		proto_parameter = NULL;
1086 		function->parameter_orig = NULL;
1087 		function->flags = ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
1088 
1089 		zbx_vector_ptr_append(functions, function);
1090 	}
1091 	else
1092 	{
1093 		if (function->itemid != itemid)
1094 		{
1095 			function->itemid_orig = function->itemid;
1096 			function->itemid = itemid;
1097 			function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID;
1098 		}
1099 
1100 		if (0 != strcmp(function->function, function_proto->function))
1101 		{
1102 			function->function_orig = function->function;
1103 			function->function = zbx_strdup(NULL, function_proto->function);
1104 			function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION;
1105 		}
1106 
1107 		if (0 != strcmp(function->parameter, proto_parameter))
1108 		{
1109 			function->parameter_orig = function->parameter;
1110 			function->parameter = proto_parameter;
1111 			proto_parameter = NULL;
1112 			function->flags |= ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER;
1113 		}
1114 
1115 		function->flags |= ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
1116 	}
1117 clean:
1118 	zbx_free(proto_parameter);
1119 
1120 	return ret;
1121 }
1122 
lld_functions_delete(zbx_vector_ptr_t * functions)1123 static void	lld_functions_delete(zbx_vector_ptr_t *functions)
1124 {
1125 	int	i;
1126 
1127 	for (i = 0; i < functions->values_num; i++)
1128 	{
1129 		zbx_lld_function_t	*function = (zbx_lld_function_t *)functions->values[i];
1130 
1131 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
1132 			continue;
1133 
1134 		function->flags |= ZBX_FLAG_LLD_FUNCTION_DELETE;
1135 	}
1136 }
1137 
lld_functions_make(const zbx_vector_ptr_t * functions_proto,zbx_vector_ptr_t * functions,const zbx_vector_ptr_t * items,const zbx_vector_ptr_t * item_links,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macros,char ** error)1138 static int	lld_functions_make(const zbx_vector_ptr_t *functions_proto, zbx_vector_ptr_t *functions,
1139 		const zbx_vector_ptr_t *items, const zbx_vector_ptr_t *item_links, const struct zbx_json_parse *jp_row,
1140 		const zbx_vector_ptr_t *lld_macros, char **error)
1141 {
1142 	int				i, index, ret = FAIL;
1143 	const zbx_lld_function_t	*function_proto;
1144 	const zbx_lld_item_t		*item_proto;
1145 	const zbx_lld_item_link_t	*item_link;
1146 	zbx_uint64_t			itemid;
1147 
1148 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1149 
1150 	for (i = 0; i < functions_proto->values_num; i++)
1151 	{
1152 		function_proto = (zbx_lld_function_t *)functions_proto->values[i];
1153 
1154 		index = zbx_vector_ptr_bsearch(items, &function_proto->itemid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1155 
1156 		if (FAIL == index)
1157 			goto out;
1158 
1159 		item_proto = (zbx_lld_item_t *)items->values[index];
1160 
1161 		if (0 != (item_proto->flags & ZBX_FLAG_DISCOVERY_PROTOTYPE))
1162 		{
1163 			index = zbx_vector_ptr_bsearch(item_links, &item_proto->itemid,
1164 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1165 
1166 			if (FAIL == index)
1167 				goto out;
1168 
1169 			item_link = (zbx_lld_item_link_t *)item_links->values[index];
1170 
1171 			itemid = item_link->itemid;
1172 		}
1173 		else
1174 			itemid = item_proto->itemid;
1175 
1176 		if (FAIL == lld_function_make(function_proto, functions, itemid, jp_row, lld_macros, error))
1177 			goto out;
1178 	}
1179 
1180 	lld_functions_delete(functions);
1181 
1182 	ret = SUCCEED;
1183 out:
1184 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1185 
1186 	return ret;
1187 }
1188 
1189 /******************************************************************************
1190  *                                                                            *
1191  * Function: lld_trigger_make                                                 *
1192  *                                                                            *
1193  * Purpose: create a trigger based on lld rule and add it to the list         *
1194  *                                                                            *
1195  ******************************************************************************/
lld_trigger_make(const zbx_lld_trigger_prototype_t * trigger_prototype,zbx_vector_ptr_t * triggers,const zbx_vector_ptr_t * items,zbx_hashset_t * items_triggers,const zbx_lld_row_t * lld_row,const zbx_vector_ptr_t * lld_macros,char ** error)1196 static void 	lld_trigger_make(const zbx_lld_trigger_prototype_t *trigger_prototype, zbx_vector_ptr_t *triggers,
1197 		const zbx_vector_ptr_t *items, zbx_hashset_t *items_triggers, const zbx_lld_row_t *lld_row,
1198 		const zbx_vector_ptr_t *lld_macros, char **error)
1199 {
1200 	zbx_lld_trigger_t		*trigger;
1201 	char				*buffer = NULL, *expression = NULL, *recovery_expression = NULL, err[64];
1202 	char				*err_msg = NULL;
1203 	const char			*operation_msg;
1204 	const struct zbx_json_parse	*jp_row = &lld_row->jp_row;
1205 	unsigned char			discover;
1206 
1207 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1208 
1209 	trigger = lld_trigger_get(trigger_prototype->triggerid, items_triggers, &lld_row->item_links);
1210 	operation_msg = NULL != trigger ? "update" : "create";
1211 
1212 	expression = zbx_strdup(expression, trigger_prototype->expression);
1213 	recovery_expression = zbx_strdup(recovery_expression, trigger_prototype->recovery_expression);
1214 
1215 	if (SUCCEED != substitute_lld_macros(&expression, jp_row, lld_macros, ZBX_MACRO_ANY | ZBX_TOKEN_TRIGGER,
1216 			err, sizeof(err)) ||
1217 			SUCCEED != substitute_lld_macros(&recovery_expression, jp_row, lld_macros,
1218 					ZBX_MACRO_ANY | ZBX_TOKEN_TRIGGER, err, sizeof(err)))
1219 	{
1220 		*error = zbx_strdcatf(*error, "Cannot %s trigger: %s.\n", operation_msg, err);
1221 		goto out;
1222 	}
1223 
1224 	discover = trigger_prototype->discover;
1225 
1226 	if (NULL != trigger)
1227 	{
1228 		unsigned char	priority;
1229 
1230 		buffer = zbx_strdup(buffer, trigger_prototype->description);
1231 		substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_FUNC, NULL, 0);
1232 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
1233 		priority = trigger_prototype->priority;
1234 
1235 		lld_override_trigger(&lld_row->overrides, buffer, &priority, &trigger->override_tags, NULL, &discover);
1236 
1237 		if (ZBX_PROTOTYPE_NO_DISCOVER == discover)
1238 			goto out;
1239 
1240 		if (0 != strcmp(trigger->description, buffer))
1241 		{
1242 			trigger->description_orig = trigger->description;
1243 			trigger->description = buffer;
1244 			buffer = NULL;
1245 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION;
1246 		}
1247 
1248 		if (trigger->priority != priority)
1249 		{
1250 			trigger->priority = priority;
1251 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY;
1252 		}
1253 
1254 		if (0 != strcmp(trigger->expression, expression))
1255 		{
1256 			trigger->expression_orig = trigger->expression;
1257 			trigger->expression = expression;
1258 			expression = NULL;
1259 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION;
1260 		}
1261 
1262 		if (0 != strcmp(trigger->recovery_expression, recovery_expression))
1263 		{
1264 			trigger->recovery_expression_orig = trigger->recovery_expression;
1265 			trigger->recovery_expression = recovery_expression;
1266 			recovery_expression = NULL;
1267 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION;
1268 		}
1269 
1270 		buffer = zbx_strdup(buffer, trigger_prototype->comments);
1271 		substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_FUNC, NULL, 0);
1272 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
1273 		if (0 != strcmp(trigger->comments, buffer))
1274 		{
1275 			trigger->comments_orig = trigger->comments;
1276 			trigger->comments = buffer;
1277 			buffer = NULL;
1278 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS;
1279 		}
1280 
1281 		buffer = zbx_strdup(buffer, trigger_prototype->url);
1282 		substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1283 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
1284 		if (0 != strcmp(trigger->url, buffer))
1285 		{
1286 			trigger->url_orig = trigger->url;
1287 			trigger->url = buffer;
1288 			buffer = NULL;
1289 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_URL;
1290 		}
1291 
1292 		buffer = zbx_strdup(buffer, trigger_prototype->correlation_tag);
1293 		substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1294 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
1295 		if (0 != strcmp(trigger->correlation_tag, buffer))
1296 		{
1297 			trigger->correlation_tag_orig = trigger->correlation_tag;
1298 			trigger->correlation_tag = buffer;
1299 			buffer = NULL;
1300 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_TAG;
1301 		}
1302 
1303 		buffer = zbx_strdup(buffer, trigger_prototype->opdata);
1304 		substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1305 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
1306 		if (0 != strcmp(trigger->opdata, buffer))
1307 		{
1308 			trigger->opdata_orig = trigger->opdata;
1309 			trigger->opdata = buffer;
1310 			buffer = NULL;
1311 			trigger->flags |= ZBX_FLAG_LLD_TRIGGER_UPDATE_OPDATA;
1312 		}
1313 	}
1314 	else
1315 	{
1316 		trigger = (zbx_lld_trigger_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
1317 
1318 		trigger->triggerid = 0;
1319 		trigger->lastcheck = 0;
1320 		trigger->ts_delete = 0;
1321 		trigger->parent_triggerid = trigger_prototype->triggerid;
1322 
1323 		trigger->description = zbx_strdup(NULL, trigger_prototype->description);
1324 		trigger->description_orig = NULL;
1325 		substitute_lld_macros(&trigger->description, jp_row, lld_macros, ZBX_MACRO_FUNC, NULL, 0);
1326 		zbx_lrtrim(trigger->description, ZBX_WHITESPACE);
1327 
1328 		trigger->status = trigger_prototype->status;
1329 		trigger->priority = trigger_prototype->priority;
1330 
1331 		zbx_vector_ptr_pair_create(&trigger->override_tags);
1332 
1333 		lld_override_trigger(&lld_row->overrides, trigger->description, &trigger->priority,
1334 				&trigger->override_tags, &trigger->status, &discover);
1335 
1336 		if (ZBX_PROTOTYPE_NO_DISCOVER == discover)
1337 		{
1338 			zbx_vector_ptr_pair_destroy(&trigger->override_tags);
1339 			zbx_free(trigger->description);
1340 			zbx_free(trigger);
1341 			goto out;
1342 		}
1343 
1344 		trigger->expression = expression;
1345 		trigger->expression_orig = NULL;
1346 		expression = NULL;
1347 
1348 		trigger->recovery_expression = recovery_expression;
1349 		trigger->recovery_expression_orig = NULL;
1350 		recovery_expression = NULL;
1351 
1352 		trigger->comments = zbx_strdup(NULL, trigger_prototype->comments);
1353 		trigger->comments_orig = NULL;
1354 		substitute_lld_macros(&trigger->comments, jp_row, lld_macros, ZBX_MACRO_FUNC, NULL, 0);
1355 		zbx_lrtrim(trigger->comments, ZBX_WHITESPACE);
1356 
1357 		trigger->url = zbx_strdup(NULL, trigger_prototype->url);
1358 		trigger->url_orig = NULL;
1359 		substitute_lld_macros(&trigger->url, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1360 		zbx_lrtrim(trigger->url, ZBX_WHITESPACE);
1361 
1362 		trigger->correlation_tag = zbx_strdup(NULL, trigger_prototype->correlation_tag);
1363 		trigger->correlation_tag_orig = NULL;
1364 		substitute_lld_macros(&trigger->correlation_tag, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1365 		zbx_lrtrim(trigger->correlation_tag, ZBX_WHITESPACE);
1366 
1367 		trigger->opdata = zbx_strdup(NULL, trigger_prototype->opdata);
1368 		trigger->opdata_orig = NULL;
1369 		substitute_lld_macros(&trigger->opdata, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1370 		zbx_lrtrim(trigger->opdata, ZBX_WHITESPACE);
1371 
1372 		zbx_vector_ptr_create(&trigger->functions);
1373 		zbx_vector_ptr_create(&trigger->dependencies);
1374 		zbx_vector_ptr_create(&trigger->dependents);
1375 		zbx_vector_ptr_create(&trigger->tags);
1376 
1377 		trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
1378 
1379 		zbx_vector_ptr_append(triggers, trigger);
1380 	}
1381 
1382 	if (SUCCEED != lld_functions_make(&trigger_prototype->functions, &trigger->functions, items,
1383 			&lld_row->item_links, jp_row, lld_macros, &err_msg))
1384 	{
1385 		if (err_msg)
1386 		{
1387 			*error = zbx_strdcatf(*error, "Cannot %s trigger: %s.\n", operation_msg, err_msg);
1388 			zbx_free(err_msg);
1389 		}
1390 		goto out;
1391 	}
1392 
1393 	trigger->flags |= ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
1394 out:
1395 	zbx_free(recovery_expression);
1396 	zbx_free(expression);
1397 	zbx_free(buffer);
1398 
1399 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1400 }
1401 
items_triggers_hash_func(const void * data)1402 static zbx_hash_t	items_triggers_hash_func(const void *data)
1403 {
1404 	const zbx_lld_item_trigger_t	*item_trigger = (zbx_lld_item_trigger_t *)data;
1405 	zbx_hash_t			hash;
1406 
1407 	hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&item_trigger->parent_triggerid);
1408 	hash = ZBX_DEFAULT_UINT64_HASH_ALGO(&item_trigger->itemid, sizeof(zbx_uint64_t), hash);
1409 
1410 	return hash;
1411 }
1412 
items_triggers_compare_func(const void * d1,const void * d2)1413 static int	items_triggers_compare_func(const void *d1, const void *d2)
1414 {
1415 	const zbx_lld_item_trigger_t	*item_trigger1 = (zbx_lld_item_trigger_t *)d1, *item_trigger2 = (zbx_lld_item_trigger_t *)d2;
1416 
1417 	ZBX_RETURN_IF_NOT_EQUAL(item_trigger1->parent_triggerid, item_trigger2->parent_triggerid);
1418 	ZBX_RETURN_IF_NOT_EQUAL(item_trigger1->itemid, item_trigger2->itemid);
1419 
1420 	return 0;
1421 }
1422 
lld_triggers_make(const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers,const zbx_vector_ptr_t * items,const zbx_vector_ptr_t * lld_rows,const zbx_vector_ptr_t * lld_macro_paths,char ** error)1423 static void	lld_triggers_make(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers,
1424 		const zbx_vector_ptr_t *items, const zbx_vector_ptr_t *lld_rows,
1425 		const zbx_vector_ptr_t *lld_macro_paths, char **error)
1426 {
1427 	const zbx_lld_trigger_prototype_t	*trigger_prototype;
1428 	int					i, j;
1429 	zbx_hashset_t				items_triggers;
1430 	zbx_lld_trigger_t			*trigger;
1431 	const zbx_lld_function_t		*function;
1432 	zbx_lld_item_trigger_t			item_trigger;
1433 
1434 	/* used for fast search of trigger by item prototype */
1435 	zbx_hashset_create(&items_triggers, 512, items_triggers_hash_func, items_triggers_compare_func);
1436 
1437 	for (i = 0; i < triggers->values_num; i++)
1438 	{
1439 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1440 
1441 		for (j = 0; j < trigger->functions.values_num; j++)
1442 		{
1443 			function = (zbx_lld_function_t *)trigger->functions.values[j];
1444 
1445 			item_trigger.parent_triggerid = trigger->parent_triggerid;
1446 			item_trigger.itemid = function->itemid;
1447 			item_trigger.trigger = trigger;
1448 			zbx_hashset_insert(&items_triggers, &item_trigger, sizeof(item_trigger));
1449 		}
1450 	}
1451 
1452 	for (i = 0; i < trigger_prototypes->values_num; i++)
1453 	{
1454 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1455 
1456 		for (j = 0; j < lld_rows->values_num; j++)
1457 		{
1458 			zbx_lld_row_t	*lld_row = (zbx_lld_row_t *)lld_rows->values[j];
1459 
1460 			lld_trigger_make(trigger_prototype, triggers, items, &items_triggers, lld_row, lld_macro_paths,
1461 					error);
1462 		}
1463 	}
1464 
1465 	zbx_hashset_destroy(&items_triggers);
1466 
1467 	zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1468 }
1469 
1470 /******************************************************************************
1471  *                                                                            *
1472  * Function: lld_trigger_dependency_make                                      *
1473  *                                                                            *
1474  * Purpose: create a trigger dependencies                                     *
1475  *                                                                            *
1476  ******************************************************************************/
lld_trigger_dependency_make(const zbx_lld_trigger_prototype_t * trigger_prototype,const zbx_vector_ptr_t * trigger_prototypes,zbx_hashset_t * items_triggers,const zbx_lld_row_t * lld_row,char ** error)1477 static void 	lld_trigger_dependency_make(const zbx_lld_trigger_prototype_t *trigger_prototype,
1478 		const zbx_vector_ptr_t *trigger_prototypes, zbx_hashset_t *items_triggers, const zbx_lld_row_t *lld_row,
1479 		char **error)
1480 {
1481 	zbx_lld_trigger_t			*trigger, *dep_trigger;
1482 	const zbx_lld_trigger_prototype_t	*dep_trigger_prototype;
1483 	zbx_lld_dependency_t			*dependency;
1484 	zbx_uint64_t				triggerid_up;
1485 	int					i, j, index;
1486 
1487 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1488 
1489 	if (NULL == (trigger = lld_trigger_get(trigger_prototype->triggerid, items_triggers, &lld_row->item_links)))
1490 		goto out;
1491 
1492 	for (i = 0; i < trigger_prototype->dependencies.values_num; i++)
1493 	{
1494 		triggerid_up = ((zbx_lld_dependency_t *)trigger_prototype->dependencies.values[i])->triggerid_up;
1495 
1496 		index = zbx_vector_ptr_bsearch(trigger_prototypes, &triggerid_up, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1497 
1498 		if (FAIL != index)
1499 		{
1500 			/* creating trigger dependency based on trigger prototype */
1501 
1502 			dep_trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
1503 
1504 			dep_trigger = lld_trigger_get(dep_trigger_prototype->triggerid, items_triggers,
1505 					&lld_row->item_links);
1506 
1507 			if (NULL != dep_trigger)
1508 			{
1509 				if (0 == dep_trigger->triggerid)
1510 				{
1511 					dependency = (zbx_lld_dependency_t *)zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1512 
1513 					dependency->triggerdepid = 0;
1514 					dependency->triggerid_up = 0;
1515 
1516 					zbx_vector_ptr_append(&trigger->dependencies, dependency);
1517 				}
1518 				else
1519 				{
1520 					int	dependency_found = 0;
1521 
1522 					for (j = 0; j < trigger->dependencies.values_num; j++)
1523 					{
1524 						dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1525 
1526 						if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1527 							continue;
1528 
1529 						if (dependency->triggerid_up == dep_trigger->triggerid)
1530 						{
1531 							dependency_found = 1;
1532 							break;
1533 						}
1534 					}
1535 
1536 					if (0 == dependency_found)
1537 					{
1538 						dependency = (zbx_lld_dependency_t *)zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1539 
1540 						dependency->triggerdepid = 0;
1541 						dependency->triggerid_up = dep_trigger->triggerid;
1542 
1543 						zbx_vector_ptr_append(&trigger->dependencies, dependency);
1544 					}
1545 				}
1546 
1547 				zbx_vector_ptr_append(&dep_trigger->dependents, trigger);
1548 
1549 				dependency->trigger_up = dep_trigger;
1550 				dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED;
1551 			}
1552 			else
1553 			{
1554 				*error = zbx_strdcatf(*error, "Cannot create dependency on trigger \"%s\".\n",
1555 						trigger->description);
1556 			}
1557 		}
1558 		else
1559 		{
1560 			/* creating trigger dependency based on generic trigger */
1561 
1562 			for (j = 0; j < trigger->dependencies.values_num; j++)
1563 			{
1564 				dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1565 
1566 				if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1567 					continue;
1568 
1569 				if (dependency->triggerid_up == triggerid_up)
1570 					break;
1571 			}
1572 
1573 			if (j == trigger->dependencies.values_num)
1574 			{
1575 				dependency = (zbx_lld_dependency_t *)zbx_malloc(NULL, sizeof(zbx_lld_dependency_t));
1576 
1577 				dependency->triggerdepid = 0;
1578 				dependency->triggerid_up = triggerid_up;
1579 				dependency->trigger_up = NULL;
1580 
1581 				zbx_vector_ptr_append(&trigger->dependencies, dependency);
1582 			}
1583 
1584 			dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED;
1585 		}
1586 	}
1587 out:
1588 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1589 }
1590 
lld_trigger_dependencies_make(const zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers,const zbx_vector_ptr_t * lld_rows,char ** error)1591 static void	lld_trigger_dependencies_make(const zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers,
1592 		const zbx_vector_ptr_t *lld_rows, char **error)
1593 {
1594 	const zbx_lld_trigger_prototype_t	*trigger_prototype;
1595 	int				i, j;
1596 	zbx_hashset_t			items_triggers;
1597 	zbx_lld_trigger_t		*trigger;
1598 	zbx_lld_function_t		*function;
1599 	zbx_lld_item_trigger_t		item_trigger;
1600 	zbx_lld_dependency_t		*dependency;
1601 
1602 	for (i = 0; i < trigger_prototypes->values_num; i++)
1603 	{
1604 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1605 
1606 		if (0 != trigger_prototype->dependencies.values_num)
1607 			break;
1608 	}
1609 
1610 	for (j = 0; j < triggers->values_num; j++)
1611 	{
1612 		trigger = (zbx_lld_trigger_t *)triggers->values[j];
1613 
1614 		if (0 != trigger->dependencies.values_num)
1615 			break;
1616 	}
1617 
1618 	/* all trigger prototypes and triggers have no dependencies */
1619 	if (i == trigger_prototypes->values_num && j == triggers->values_num)
1620 		return;
1621 
1622 	/* used for fast search of trigger by item prototype */
1623 	zbx_hashset_create(&items_triggers, 512, items_triggers_hash_func, items_triggers_compare_func);
1624 
1625 	for (i = 0; i < triggers->values_num; i++)
1626 	{
1627 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1628 
1629 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1630 			continue;
1631 
1632 		for (j = 0; j < trigger->functions.values_num; j++)
1633 		{
1634 			function = (zbx_lld_function_t *)trigger->functions.values[j];
1635 
1636 			item_trigger.parent_triggerid = trigger->parent_triggerid;
1637 			item_trigger.itemid = function->itemid;
1638 			item_trigger.trigger = trigger;
1639 			zbx_hashset_insert(&items_triggers, &item_trigger, sizeof(item_trigger));
1640 		}
1641 	}
1642 
1643 	for (i = 0; i < trigger_prototypes->values_num; i++)
1644 	{
1645 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1646 
1647 		for (j = 0; j < lld_rows->values_num; j++)
1648 		{
1649 			zbx_lld_row_t	*lld_row = (zbx_lld_row_t *)lld_rows->values[j];
1650 
1651 			lld_trigger_dependency_make(trigger_prototype, trigger_prototypes,
1652 					&items_triggers, lld_row, error);
1653 		}
1654 	}
1655 
1656 	/* marking dependencies which will be deleted */
1657 	for (i = 0; i < triggers->values_num; i++)
1658 	{
1659 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1660 
1661 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1662 			continue;
1663 
1664 		for (j = 0; j < trigger->dependencies.values_num; j++)
1665 		{
1666 			dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
1667 
1668 			if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
1669 				dependency->flags = ZBX_FLAG_LLD_DEPENDENCY_DELETE;
1670 		}
1671 	}
1672 
1673 	zbx_hashset_destroy(&items_triggers);
1674 
1675 	zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1676 }
1677 
ptr_pair_compare_func(const void * d1,const void * d2)1678 static int	ptr_pair_compare_func(const void *d1, const void *d2)
1679 {
1680 	const zbx_ptr_pair_t	*pair1 = (const zbx_ptr_pair_t *)d1;
1681 	const zbx_ptr_pair_t	*pair2 = (const zbx_ptr_pair_t *)d2;
1682 	int			ret;
1683 
1684 	if (0 != (ret = strcmp((char *)pair1->first, (char *)pair2->first)))
1685 		return ret;
1686 
1687 	return strcmp((char *)pair1->second, (char *)pair2->second);
1688 }
1689 
1690 /******************************************************************************
1691  *                                                                            *
1692  * Function: lld_trigger_tag_make                                             *
1693  *                                                                            *
1694  * Purpose: create a trigger tag                                              *
1695  *                                                                            *
1696  ******************************************************************************/
lld_trigger_tag_make(zbx_lld_trigger_prototype_t * trigger_prototype,zbx_hashset_t * items_triggers,zbx_lld_row_t * lld_row,const zbx_vector_ptr_t * lld_macro_paths)1697 static void 	lld_trigger_tag_make(zbx_lld_trigger_prototype_t *trigger_prototype,
1698 		zbx_hashset_t *items_triggers, zbx_lld_row_t *lld_row, const zbx_vector_ptr_t *lld_macro_paths)
1699 {
1700 	zbx_lld_trigger_t	*trigger;
1701 	int			i;
1702 	zbx_lld_tag_t		*tag;
1703 	char			*buffer = NULL;
1704 	const char		*key, *value;
1705 
1706 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1707 
1708 	if (NULL == (trigger = lld_trigger_get(trigger_prototype->triggerid, items_triggers, &lld_row->item_links)))
1709 		goto out;
1710 
1711 	zbx_vector_ptr_pair_sort(&trigger->override_tags, ptr_pair_compare_func);
1712 
1713 	for (i = 0; i < trigger_prototype->tags.values_num + trigger->override_tags.values_num; i++)
1714 	{
1715 		if (i < trigger_prototype->tags.values_num)
1716 		{
1717 			zbx_lld_tag_t	*tag_proto;
1718 
1719 			tag_proto = (zbx_lld_tag_t *)trigger_prototype->tags.values[i];
1720 			key = tag_proto->tag;
1721 			value = tag_proto->value;
1722 		}
1723 		else
1724 		{
1725 			zbx_ptr_pair_t	pair;
1726 
1727 			pair = trigger->override_tags.values[i - trigger_prototype->tags.values_num];
1728 			key = pair.first;
1729 			value = pair.second;
1730 		}
1731 
1732 		if (i < trigger->tags.values_num)
1733 		{
1734 			tag = (zbx_lld_tag_t *)trigger->tags.values[i];
1735 
1736 			buffer = zbx_strdup(buffer, key);
1737 			substitute_lld_macros(&buffer, &lld_row->jp_row, lld_macro_paths, ZBX_MACRO_FUNC, NULL, 0);
1738 			zbx_lrtrim(buffer, ZBX_WHITESPACE);
1739 			if (0 != strcmp(buffer, tag->tag))
1740 			{
1741 				zbx_free(tag->tag);
1742 				tag->tag = buffer;
1743 				buffer = NULL;
1744 				tag->flags |= ZBX_FLAG_LLD_TAG_UPDATE_TAG;
1745 			}
1746 
1747 			buffer = zbx_strdup(buffer, value);
1748 			substitute_lld_macros(&buffer, &lld_row->jp_row, lld_macro_paths, ZBX_MACRO_FUNC, NULL, 0);
1749 			zbx_lrtrim(buffer, ZBX_WHITESPACE);
1750 			if (0 != strcmp(buffer, tag->value))
1751 			{
1752 				zbx_free(tag->value);
1753 				tag->value = buffer;
1754 				buffer = NULL;
1755 				tag->flags |= ZBX_FLAG_LLD_TAG_UPDATE_VALUE;
1756 			}
1757 		}
1758 		else
1759 		{
1760 			tag = (zbx_lld_tag_t *)zbx_malloc(NULL, sizeof(zbx_lld_tag_t));
1761 
1762 			tag->triggertagid = 0;
1763 
1764 			tag->tag = zbx_strdup(NULL, key);
1765 			substitute_lld_macros(&tag->tag, &lld_row->jp_row, lld_macro_paths, ZBX_MACRO_FUNC, NULL, 0);
1766 			zbx_lrtrim(tag->tag, ZBX_WHITESPACE);
1767 
1768 			tag->value = zbx_strdup(NULL, value);
1769 			substitute_lld_macros(&tag->value, &lld_row->jp_row, lld_macro_paths, ZBX_MACRO_FUNC, NULL, 0);
1770 			zbx_lrtrim(tag->value, ZBX_WHITESPACE);
1771 
1772 			tag->flags = ZBX_FLAG_LLD_TAG_UNSET;
1773 
1774 			zbx_vector_ptr_append(&trigger->tags, tag);
1775 
1776 		}
1777 
1778 		tag->flags |= ZBX_FLAG_LLD_TAG_DISCOVERED;
1779 	}
1780 out:
1781 	zbx_free(buffer);
1782 
1783 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1784 }
1785 
1786 /******************************************************************************
1787  *                                                                            *
1788  * Function: lld_trigger_tags_make                                            *
1789  *                                                                            *
1790  * Purpose: create a trigger tags                                             *
1791  *                                                                            *
1792  ******************************************************************************/
lld_trigger_tags_make(zbx_vector_ptr_t * trigger_prototypes,zbx_vector_ptr_t * triggers,const zbx_vector_ptr_t * lld_rows,const zbx_vector_ptr_t * lld_macro_paths)1793 static void	lld_trigger_tags_make(zbx_vector_ptr_t *trigger_prototypes, zbx_vector_ptr_t *triggers,
1794 		const zbx_vector_ptr_t *lld_rows, const zbx_vector_ptr_t *lld_macro_paths)
1795 {
1796 	zbx_lld_trigger_prototype_t	*trigger_prototype;
1797 	int				i, j;
1798 	zbx_hashset_t			items_triggers;
1799 	zbx_lld_trigger_t		*trigger;
1800 	zbx_lld_function_t		*function;
1801 	zbx_lld_item_trigger_t		item_trigger;
1802 	zbx_lld_tag_t			*tag;
1803 
1804 	/* used for fast search of trigger by item prototype */
1805 	zbx_hashset_create(&items_triggers, 512, items_triggers_hash_func, items_triggers_compare_func);
1806 
1807 	for (i = 0; i < triggers->values_num; i++)
1808 	{
1809 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1810 
1811 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1812 			continue;
1813 
1814 		for (j = 0; j < trigger->functions.values_num; j++)
1815 		{
1816 			function = (zbx_lld_function_t *)trigger->functions.values[j];
1817 
1818 			item_trigger.parent_triggerid = trigger->parent_triggerid;
1819 			item_trigger.itemid = function->itemid;
1820 			item_trigger.trigger = trigger;
1821 			zbx_hashset_insert(&items_triggers, &item_trigger, sizeof(item_trigger));
1822 		}
1823 	}
1824 
1825 	for (i = 0; i < trigger_prototypes->values_num; i++)
1826 	{
1827 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
1828 
1829 		for (j = 0; j < lld_rows->values_num; j++)
1830 		{
1831 			zbx_lld_row_t	*lld_row = (zbx_lld_row_t *)lld_rows->values[j];
1832 
1833 			lld_trigger_tag_make(trigger_prototype, &items_triggers, lld_row, lld_macro_paths);
1834 		}
1835 	}
1836 
1837 	/* marking tags which will be deleted */
1838 	for (i = 0; i < triggers->values_num; i++)
1839 	{
1840 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
1841 
1842 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1843 			continue;
1844 
1845 		for (j = 0; j < trigger->tags.values_num; j++)
1846 		{
1847 			tag = (zbx_lld_tag_t *)trigger->tags.values[j];
1848 
1849 			if (0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
1850 				tag->flags = ZBX_FLAG_LLD_TAG_DELETE;
1851 		}
1852 	}
1853 
1854 	zbx_hashset_destroy(&items_triggers);
1855 
1856 	zbx_vector_ptr_sort(triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1857 }
1858 
1859 /******************************************************************************
1860  *                                                                            *
1861  * Function: lld_validate_trigger_field                                       *
1862  *                                                                            *
1863  ******************************************************************************/
lld_validate_trigger_field(zbx_lld_trigger_t * trigger,char ** field,char ** field_orig,zbx_uint64_t flag,size_t field_len,char ** error)1864 static void	lld_validate_trigger_field(zbx_lld_trigger_t *trigger, char **field, char **field_orig,
1865 		zbx_uint64_t flag, size_t field_len, char **error)
1866 {
1867 	if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
1868 		return;
1869 
1870 	/* only new triggers or triggers with changed data will be validated */
1871 	if (0 != trigger->triggerid && 0 == (trigger->flags & flag))
1872 		return;
1873 
1874 	if (SUCCEED != zbx_is_utf8(*field))
1875 	{
1876 		zbx_replace_invalid_utf8(*field);
1877 		*error = zbx_strdcatf(*error, "Cannot %s trigger: value \"%s\" has invalid UTF-8 sequence.\n",
1878 				(0 != trigger->triggerid ? "update" : "create"), *field);
1879 	}
1880 	else if (zbx_strlen_utf8(*field) > field_len)
1881 	{
1882 		*error = zbx_strdcatf(*error, "Cannot %s trigger: value \"%s\" is too long.\n",
1883 				(0 != trigger->triggerid ? "update" : "create"), *field);
1884 	}
1885 	else if (ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION == flag && '\0' == **field)
1886 	{
1887 		*error = zbx_strdcatf(*error, "Cannot %s trigger: name is empty.\n",
1888 				(0 != trigger->triggerid ? "update" : "create"));
1889 	}
1890 	else
1891 		return;
1892 
1893 	if (0 != trigger->triggerid)
1894 		lld_field_str_rollback(field, field_orig, &trigger->flags, flag);
1895 	else
1896 		trigger->flags &= ~ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
1897 }
1898 
1899 /******************************************************************************
1900  *                                                                            *
1901  * Function: lld_trigger_changed                                              *
1902  *                                                                            *
1903  * Return value: returns SUCCEED if a trigger description or expression has   *
1904  *               been changed; FAIL - otherwise                               *
1905  *                                                                            *
1906  ******************************************************************************/
lld_trigger_changed(const zbx_lld_trigger_t * trigger)1907 static int	lld_trigger_changed(const zbx_lld_trigger_t *trigger)
1908 {
1909 	int			i;
1910 	zbx_lld_function_t	*function;
1911 
1912 	if (0 == trigger->triggerid)
1913 		return SUCCEED;
1914 
1915 	if (0 != (trigger->flags & (ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION | ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION |
1916 			ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION)))
1917 	{
1918 		return SUCCEED;
1919 	}
1920 
1921 	for (i = 0; i < trigger->functions.values_num; i++)
1922 	{
1923 		function = (zbx_lld_function_t *)trigger->functions.values[i];
1924 
1925 		if (0 == function->functionid)
1926 		{
1927 			THIS_SHOULD_NEVER_HAPPEN;
1928 			return SUCCEED;
1929 		}
1930 
1931 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE))
1932 			return SUCCEED;
1933 	}
1934 
1935 	return FAIL;
1936 }
1937 
1938 /******************************************************************************
1939  *                                                                            *
1940  * Function: lld_triggers_equal                                               *
1941  *                                                                            *
1942  * Return value: returns SUCCEED if descriptions and expressions of           *
1943  *               the triggers are identical; FAIL - otherwise                 *
1944  *                                                                            *
1945  ******************************************************************************/
lld_triggers_equal(const zbx_lld_trigger_t * trigger,const zbx_lld_trigger_t * trigger_b)1946 static int	lld_triggers_equal(const zbx_lld_trigger_t *trigger, const zbx_lld_trigger_t *trigger_b)
1947 {
1948 	int	ret = FAIL;
1949 
1950 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1951 
1952 	if (0 == strcmp(trigger->description, trigger_b->description))
1953 	{
1954 		char	*expression, *expression_b;
1955 
1956 		expression = lld_expression_expand(trigger->expression, &trigger->functions);
1957 		expression_b = lld_expression_expand(trigger_b->expression, &trigger_b->functions);
1958 
1959 		if (0 == strcmp(expression, expression_b))
1960 		{
1961 			zbx_free(expression);
1962 			zbx_free(expression_b);
1963 
1964 			expression = lld_expression_expand(trigger->recovery_expression, &trigger->functions);
1965 			expression_b = lld_expression_expand(trigger_b->recovery_expression, &trigger_b->functions);
1966 
1967 			if (0 == strcmp(expression, expression_b))
1968 				ret = SUCCEED;
1969 		}
1970 
1971 		zbx_free(expression);
1972 		zbx_free(expression_b);
1973 	}
1974 
1975 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1976 
1977 	return ret;
1978 }
1979 
1980 /******************************************************************************
1981  *                                                                            *
1982  * Function: lld_triggers_validate                                            *
1983  *                                                                            *
1984  * Parameters: triggers - [IN] sorted list of triggers                        *
1985  *                                                                            *
1986  ******************************************************************************/
lld_triggers_validate(zbx_uint64_t hostid,zbx_vector_ptr_t * triggers,char ** error)1987 static void	lld_triggers_validate(zbx_uint64_t hostid, zbx_vector_ptr_t *triggers, char **error)
1988 {
1989 	int			i, j, k;
1990 	zbx_lld_trigger_t	*trigger;
1991 	zbx_lld_function_t	*function;
1992 	zbx_vector_uint64_t	triggerids;
1993 	zbx_vector_str_t	descriptions;
1994 
1995 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1996 
1997 	zbx_vector_uint64_create(&triggerids);
1998 	zbx_vector_str_create(&descriptions);
1999 
2000 	/* checking a validity of the fields */
2001 
2002 	for (i = 0; i < triggers->values_num; i++)
2003 	{
2004 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
2005 
2006 		lld_validate_trigger_field(trigger, &trigger->description, &trigger->description_orig,
2007 				ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION, TRIGGER_DESCRIPTION_LEN, error);
2008 		lld_validate_trigger_field(trigger, &trigger->comments, &trigger->comments_orig,
2009 				ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS, TRIGGER_COMMENTS_LEN, error);
2010 		lld_validate_trigger_field(trigger, &trigger->url, &trigger->url_orig,
2011 				ZBX_FLAG_LLD_TRIGGER_UPDATE_URL, TRIGGER_URL_LEN, error);
2012 		lld_validate_trigger_field(trigger, &trigger->correlation_tag, &trigger->correlation_tag_orig,
2013 				ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_TAG, TAG_NAME_LEN, error);
2014 		lld_validate_trigger_field(trigger, &trigger->opdata, &trigger->opdata_orig,
2015 				ZBX_FLAG_LLD_TRIGGER_UPDATE_OPDATA, TRIGGER_OPDATA_LEN, error);
2016 	}
2017 
2018 	/* checking duplicated triggers in DB */
2019 
2020 	for (i = 0; i < triggers->values_num; i++)
2021 	{
2022 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
2023 
2024 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2025 			continue;
2026 
2027 		if (0 != trigger->triggerid)
2028 		{
2029 			zbx_vector_uint64_append(&triggerids, trigger->triggerid);
2030 
2031 			if (SUCCEED != lld_trigger_changed(trigger))
2032 				continue;
2033 		}
2034 
2035 		zbx_vector_str_append(&descriptions, trigger->description);
2036 	}
2037 
2038 	if (0 != descriptions.values_num)
2039 	{
2040 		char			*sql = NULL;
2041 		size_t			sql_alloc = 256, sql_offset = 0;
2042 		DB_RESULT		result;
2043 		DB_ROW			row;
2044 		zbx_vector_ptr_t	db_triggers;
2045 		zbx_lld_trigger_t	*db_trigger;
2046 
2047 		zbx_vector_ptr_create(&db_triggers);
2048 
2049 		zbx_vector_str_sort(&descriptions, ZBX_DEFAULT_STR_COMPARE_FUNC);
2050 		zbx_vector_str_uniq(&descriptions, ZBX_DEFAULT_STR_COMPARE_FUNC);
2051 
2052 		sql = (char *)zbx_malloc(sql, sql_alloc);
2053 
2054 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2055 				"select distinct t.triggerid,t.description,t.expression,t.recovery_expression"
2056 				" from triggers t,functions f,items i"
2057 				" where t.triggerid=f.triggerid"
2058 					" and f.itemid=i.itemid"
2059 					" and i.hostid=" ZBX_FS_UI64
2060 					" and",
2061 				hostid);
2062 		DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.description",
2063 				(const char **)descriptions.values, descriptions.values_num);
2064 
2065 		if (0 != triggerids.values_num)
2066 		{
2067 			zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2068 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
2069 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.triggerid",
2070 					triggerids.values, triggerids.values_num);
2071 		}
2072 
2073 		result = DBselect("%s", sql);
2074 
2075 		while (NULL != (row = DBfetch(result)))
2076 		{
2077 			db_trigger = (zbx_lld_trigger_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_t));
2078 
2079 			ZBX_STR2UINT64(db_trigger->triggerid, row[0]);
2080 			db_trigger->description = zbx_strdup(NULL, row[1]);
2081 			db_trigger->description_orig = NULL;
2082 			db_trigger->expression = zbx_strdup(NULL, row[2]);
2083 			db_trigger->expression_orig = NULL;
2084 			db_trigger->recovery_expression = zbx_strdup(NULL, row[3]);
2085 			db_trigger->recovery_expression_orig = NULL;
2086 			db_trigger->comments = NULL;
2087 			db_trigger->comments_orig = NULL;
2088 			db_trigger->url = NULL;
2089 			db_trigger->url_orig = NULL;
2090 			db_trigger->correlation_tag = NULL;
2091 			db_trigger->correlation_tag_orig = NULL;
2092 			db_trigger->opdata = NULL;
2093 			db_trigger->opdata_orig = NULL;
2094 			db_trigger->flags = ZBX_FLAG_LLD_TRIGGER_UNSET;
2095 
2096 			zbx_vector_ptr_create(&db_trigger->functions);
2097 			zbx_vector_ptr_create(&db_trigger->dependencies);
2098 			zbx_vector_ptr_create(&db_trigger->dependents);
2099 			zbx_vector_ptr_create(&db_trigger->tags);
2100 			zbx_vector_ptr_pair_create(&db_trigger->override_tags);
2101 
2102 			zbx_vector_ptr_append(&db_triggers, db_trigger);
2103 		}
2104 		DBfree_result(result);
2105 
2106 		zbx_vector_ptr_sort(&db_triggers, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2107 
2108 		lld_functions_get(NULL, &db_triggers);
2109 
2110 		for (i = 0; i < db_triggers.values_num; i++)
2111 		{
2112 			db_trigger = (zbx_lld_trigger_t *)db_triggers.values[i];
2113 
2114 			lld_expressions_simplify(&db_trigger->expression, &db_trigger->recovery_expression,
2115 					&db_trigger->functions);
2116 
2117 			for (j = 0; j < triggers->values_num; j++)
2118 			{
2119 				trigger = (zbx_lld_trigger_t *)triggers->values[j];
2120 
2121 				if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2122 					continue;
2123 
2124 				if (SUCCEED != lld_triggers_equal(trigger, db_trigger))
2125 					continue;
2126 
2127 				*error = zbx_strdcatf(*error, "Cannot %s trigger: trigger \"%s\" already exists.\n",
2128 						(0 != trigger->triggerid ? "update" : "create"), trigger->description);
2129 
2130 				if (0 != trigger->triggerid)
2131 				{
2132 					lld_field_str_rollback(&trigger->description, &trigger->description_orig,
2133 							&trigger->flags, ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION);
2134 
2135 					lld_field_str_rollback(&trigger->expression, &trigger->expression_orig,
2136 							&trigger->flags, ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION);
2137 
2138 					lld_field_str_rollback(&trigger->recovery_expression,
2139 							&trigger->recovery_expression_orig, &trigger->flags,
2140 							ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION);
2141 
2142 					for (k = 0; k < trigger->functions.values_num; k++)
2143 					{
2144 						function = (zbx_lld_function_t *)trigger->functions.values[k];
2145 
2146 						if (0 != function->functionid)
2147 						{
2148 							lld_field_uint64_rollback(&function->itemid,
2149 									&function->itemid_orig,
2150 									&function->flags,
2151 									ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID);
2152 
2153 							lld_field_str_rollback(&function->function,
2154 									&function->function_orig,
2155 									&function->flags,
2156 									ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION);
2157 
2158 							lld_field_str_rollback(&function->parameter,
2159 									&function->parameter_orig,
2160 									&function->flags,
2161 									ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER);
2162 
2163 							function->flags &= ~ZBX_FLAG_LLD_FUNCTION_DELETE;
2164 						}
2165 						else
2166 							function->flags &= ~ZBX_FLAG_LLD_FUNCTION_DISCOVERED;
2167 					}
2168 				}
2169 				else
2170 					trigger->flags &= ~ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
2171 
2172 				break;	/* only one same trigger can be here */
2173 			}
2174 		}
2175 
2176 		zbx_vector_ptr_clear_ext(&db_triggers, (zbx_clean_func_t)lld_trigger_free);
2177 		zbx_vector_ptr_destroy(&db_triggers);
2178 
2179 		zbx_free(sql);
2180 	}
2181 
2182 	zbx_vector_str_destroy(&descriptions);
2183 	zbx_vector_uint64_destroy(&triggerids);
2184 
2185 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2186 }
2187 
2188 /******************************************************************************
2189  *                                                                            *
2190  * Function: lld_validate_trigger_tag_field                                   *
2191  *                                                                            *
2192  ******************************************************************************/
lld_validate_trigger_tag_field(zbx_lld_tag_t * tag,const char * field,zbx_uint64_t flag,size_t field_len,char ** error)2193 static void	lld_validate_trigger_tag_field(zbx_lld_tag_t *tag, const char *field, zbx_uint64_t flag,
2194 		size_t field_len, char **error)
2195 {
2196 	size_t	len;
2197 
2198 	if (0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
2199 		return;
2200 
2201 	/* only new trigger tags or tags with changed data will be validated */
2202 	if (0 != tag->triggertagid && 0 == (tag->flags & flag))
2203 		return;
2204 
2205 	if (SUCCEED != zbx_is_utf8(field))
2206 	{
2207 		char	*field_utf8;
2208 
2209 		field_utf8 = zbx_strdup(NULL, field);
2210 		zbx_replace_invalid_utf8(field_utf8);
2211 		*error = zbx_strdcatf(*error, "Cannot create trigger tag: value \"%s\" has invalid UTF-8 sequence.\n",
2212 				field_utf8);
2213 		zbx_free(field_utf8);
2214 	}
2215 	else if ((len = zbx_strlen_utf8(field)) > field_len)
2216 		*error = zbx_strdcatf(*error, "Cannot create trigger tag: value \"%s\" is too long.\n", field);
2217 	else if (0 != (flag & ZBX_FLAG_LLD_TAG_UPDATE_TAG) && 0 == len)
2218 		*error = zbx_strdcatf(*error, "Cannot create trigger tag: empty tag name.\n");
2219 	else
2220 		return;
2221 
2222 	if (0 != tag->triggertagid)
2223 		tag->flags = ZBX_FLAG_LLD_TAG_DELETE;
2224 	else
2225 		tag->flags &= ~ZBX_FLAG_LLD_TAG_DISCOVERED;
2226 }
2227 
2228 /******************************************************************************
2229  *                                                                            *
2230  * Function: lld_trigger_tags_validate                                        *
2231  *                                                                            *
2232  * Purpose: validate created or updated trigger tags                          *
2233  *                                                                            *
2234  ******************************************************************************/
lld_trigger_tags_validate(zbx_vector_ptr_t * triggers,char ** error)2235 static void	lld_trigger_tags_validate(zbx_vector_ptr_t *triggers, char **error)
2236 {
2237 	int			i, j, k;
2238 	zbx_lld_trigger_t	*trigger;
2239 	zbx_lld_tag_t		*tag, *tag_tmp;
2240 
2241 	for (i = 0; i < triggers->values_num; i++)
2242 	{
2243 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
2244 
2245 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2246 			continue;
2247 
2248 		for (j = 0; j < trigger->tags.values_num; j++)
2249 		{
2250 			tag = (zbx_lld_tag_t *)trigger->tags.values[j];
2251 
2252 			lld_validate_trigger_tag_field(tag, tag->tag, ZBX_FLAG_LLD_TAG_UPDATE_TAG,
2253 					TAG_NAME_LEN, error);
2254 			lld_validate_trigger_tag_field(tag, tag->value, ZBX_FLAG_LLD_TAG_UPDATE_VALUE,
2255 					TAG_VALUE_LEN, error);
2256 
2257 			if (0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
2258 				continue;
2259 
2260 			/* check for duplicated tag,values pairs */
2261 			for (k = 0; k < j; k++)
2262 			{
2263 				tag_tmp = (zbx_lld_tag_t *)trigger->tags.values[k];
2264 
2265 				if (0 == strcmp(tag->tag, tag_tmp->tag) && 0 == strcmp(tag->value, tag_tmp->value))
2266 				{
2267 					*error = zbx_strdcatf(*error, "Cannot create trigger tag: tag \"%s\","
2268 						"\"%s\" already exists.\n", tag->tag, tag->value);
2269 
2270 					if (0 != tag->triggertagid)
2271 						tag->flags = ZBX_FLAG_LLD_TAG_DELETE;
2272 					else
2273 						tag->flags &= ~ZBX_FLAG_LLD_TAG_DISCOVERED;
2274 				}
2275 			}
2276 
2277 			/* reset trigger discovery flags for new trigger if tag discovery failed */
2278 			if (0 == trigger->triggerid && 0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
2279 			{
2280 				trigger->flags &= ~ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
2281 				break;
2282 			}
2283 		}
2284 	}
2285 }
2286 
2287 /******************************************************************************
2288  *                                                                            *
2289  * Function: lld_expression_create                                            *
2290  *                                                                            *
2291  * Purpose: transforms the simple trigger expression to the DB format         *
2292  *                                                                            *
2293  * Example:                                                                   *
2294  *                                                                            *
2295  *     "{1} > 5" => "{84756} > 5"                                             *
2296  *       ^            ^                                                       *
2297  *       |            functionid from the database                            *
2298  *       internal function index                                              *
2299  *                                                                            *
2300  ******************************************************************************/
lld_expression_create(char ** expression,const zbx_vector_ptr_t * functions)2301 static void	lld_expression_create(char **expression, const zbx_vector_ptr_t *functions)
2302 {
2303 	size_t		l, r;
2304 	int		i;
2305 	zbx_uint64_t	function_index;
2306 	char		buffer[ZBX_MAX_UINT64_LEN];
2307 
2308 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __func__, *expression);
2309 
2310 	for (l = 0; '\0' != (*expression)[l]; l++)
2311 	{
2312 		if ('{' != (*expression)[l])
2313 			continue;
2314 
2315 		if ('$' == (*expression)[l + 1])
2316 		{
2317 			int	macro_r, context_l, context_r;
2318 
2319 			if (SUCCEED == zbx_user_macro_parse(*expression + l, &macro_r, &context_l, &context_r, NULL))
2320 				l += macro_r;
2321 			else
2322 				l++;
2323 
2324 			continue;
2325 		}
2326 
2327 		for (r = l + 1; '\0' != (*expression)[r] && '}' != (*expression)[r]; r++)
2328 			;
2329 
2330 		if ('}' != (*expression)[r])
2331 			continue;
2332 
2333 		/* ... > 0 | {1} + ... */
2334 		/*           l r       */
2335 
2336 		if (SUCCEED != is_uint64_n(*expression + l + 1, r - l - 1, &function_index))
2337 			continue;
2338 
2339 		for (i = 0; i < functions->values_num; i++)
2340 		{
2341 			const zbx_lld_function_t	*function = (zbx_lld_function_t *)functions->values[i];
2342 
2343 			if (function->index != function_index)
2344 				continue;
2345 
2346 			zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_UI64, function->functionid);
2347 
2348 			r--;
2349 			zbx_replace_string(expression, l + 1, &r, buffer);
2350 			r++;
2351 
2352 			break;
2353 		}
2354 
2355 		l = r;
2356 	}
2357 
2358 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() expression:'%s'", __func__, *expression);
2359 }
2360 
2361 /******************************************************************************
2362  *                                                                            *
2363  * Function: lld_triggers_save                                                *
2364  *                                                                            *
2365  * Purpose: add or update triggers in database based on discovery rule        *
2366  *                                                                            *
2367  * Parameters: hostid            - [IN] parent host id                        *
2368  *             lld_triggers_save - [IN] trigger prototypes                    *
2369  *             triggers          - [IN/OUT] triggers to save                  *
2370  *                                                                            *
2371  * Return value: SUCCEED - if triggers was successfully saved or saving       *
2372  *                         was not necessary                                  *
2373  *               FAIL    - triggers cannot be saved                           *
2374  *                                                                            *
2375  ******************************************************************************/
lld_triggers_save(zbx_uint64_t hostid,const zbx_vector_ptr_t * trigger_prototypes,const zbx_vector_ptr_t * triggers)2376 static int	lld_triggers_save(zbx_uint64_t hostid, const zbx_vector_ptr_t *trigger_prototypes,
2377 		const zbx_vector_ptr_t *triggers)
2378 {
2379 	int					ret = SUCCEED, i, j, new_triggers = 0, upd_triggers = 0, new_functions = 0,
2380 						new_dependencies = 0, new_tags = 0, upd_tags = 0;
2381 	const zbx_lld_trigger_prototype_t	*trigger_prototype;
2382 	zbx_lld_trigger_t			*trigger;
2383 	zbx_lld_function_t			*function;
2384 	zbx_lld_dependency_t			*dependency;
2385 	zbx_lld_tag_t				*tag;
2386 	zbx_vector_ptr_t			upd_functions;	/* the ordered list of functions which will be updated */
2387 	zbx_vector_uint64_t			del_functionids, del_triggerdepids, del_triggertagids, trigger_protoids;
2388 	zbx_uint64_t				triggerid = 0, functionid = 0, triggerdepid = 0, triggerid_up, triggertagid;
2389 	char					*sql = NULL, *function_esc, *parameter_esc;
2390 	size_t					sql_alloc = 8 * ZBX_KIBIBYTE, sql_offset = 0;
2391 	zbx_db_insert_t				db_insert, db_insert_tdiscovery, db_insert_tfunctions, db_insert_tdepends,
2392 						db_insert_ttags;
2393 
2394 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2395 
2396 	zbx_vector_ptr_create(&upd_functions);
2397 	zbx_vector_uint64_create(&del_functionids);
2398 	zbx_vector_uint64_create(&del_triggerdepids);
2399 	zbx_vector_uint64_create(&del_triggertagids);
2400 	zbx_vector_uint64_create(&trigger_protoids);
2401 
2402 	for (i = 0; i < triggers->values_num; i++)
2403 	{
2404 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
2405 
2406 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2407 			continue;
2408 
2409 		if (0 == trigger->triggerid)
2410 			new_triggers++;
2411 		else if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE))
2412 			upd_triggers++;
2413 
2414 		for (j = 0; j < trigger->functions.values_num; j++)
2415 		{
2416 			function = (zbx_lld_function_t *)trigger->functions.values[j];
2417 
2418 			if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DELETE))
2419 			{
2420 				zbx_vector_uint64_append(&del_functionids, function->functionid);
2421 				continue;
2422 			}
2423 
2424 			if (0 == (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
2425 				continue;
2426 
2427 			if (0 == function->functionid)
2428 				new_functions++;
2429 			else if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE))
2430 				zbx_vector_ptr_append(&upd_functions, function);
2431 		}
2432 
2433 		for (j = 0; j < trigger->dependencies.values_num; j++)
2434 		{
2435 			dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
2436 
2437 			if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DELETE))
2438 			{
2439 				zbx_vector_uint64_append(&del_triggerdepids, dependency->triggerdepid);
2440 				continue;
2441 			}
2442 
2443 			if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
2444 				continue;
2445 
2446 			if (0 == dependency->triggerdepid)
2447 				new_dependencies++;
2448 		}
2449 
2450 		for (j = 0; j < trigger->tags.values_num; j++)
2451 		{
2452 			tag = (zbx_lld_tag_t *)trigger->tags.values[j];
2453 
2454 			if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_DELETE))
2455 			{
2456 				zbx_vector_uint64_append(&del_triggertagids, tag->triggertagid);
2457 				continue;
2458 			}
2459 
2460 			if (0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
2461 				continue;
2462 
2463 			if (0 == tag->triggertagid)
2464 				new_tags++;
2465 			else if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_UPDATE))
2466 				upd_tags++;
2467 		}
2468 	}
2469 
2470 	if (0 == new_triggers && 0 == new_functions && 0 == new_dependencies && 0 == upd_triggers &&
2471 			0 == upd_functions.values_num && 0 == del_functionids.values_num &&
2472 			0 == del_triggerdepids.values_num && 0 == new_tags && 0 == upd_tags &&
2473 			0 == del_triggertagids.values_num)
2474 	{
2475 		goto out;
2476 	}
2477 
2478 	DBbegin();
2479 
2480 	for (i = 0; i < trigger_prototypes->values_num; i++)
2481 	{
2482 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[i];
2483 		zbx_vector_uint64_append(&trigger_protoids, trigger_prototype->triggerid);
2484 	}
2485 
2486 	if (SUCCEED != DBlock_hostid(hostid) || SUCCEED != DBlock_triggerids(&trigger_protoids))
2487 	{
2488 		/* the host or trigger prototype was removed while processing lld rule */
2489 		DBrollback();
2490 		ret = FAIL;
2491 		goto out;
2492 	}
2493 
2494 	if (0 != new_triggers)
2495 	{
2496 		triggerid = DBget_maxid_num("triggers", new_triggers);
2497 
2498 		zbx_db_insert_prepare(&db_insert, "triggers", "triggerid", "description", "expression", "priority",
2499 				"status", "comments", "url", "type", "value", "state", "flags", "recovery_mode",
2500 				"recovery_expression", "correlation_mode", "correlation_tag", "manual_close", "opdata",
2501 				NULL);
2502 
2503 		zbx_db_insert_prepare(&db_insert_tdiscovery, "trigger_discovery", "triggerid", "parent_triggerid",
2504 				NULL);
2505 	}
2506 
2507 	if (0 != new_functions)
2508 	{
2509 		functionid = DBget_maxid_num("functions", new_functions);
2510 
2511 		zbx_db_insert_prepare(&db_insert_tfunctions, "functions", "functionid", "itemid", "triggerid",
2512 				"name", "parameter", NULL);
2513 	}
2514 
2515 	if (0 != new_dependencies)
2516 	{
2517 		triggerdepid = DBget_maxid_num("trigger_depends", new_dependencies);
2518 
2519 		zbx_db_insert_prepare(&db_insert_tdepends, "trigger_depends", "triggerdepid", "triggerid_down",
2520 				"triggerid_up", NULL);
2521 	}
2522 
2523 	if (0 != new_tags)
2524 	{
2525 		triggertagid = DBget_maxid_num("trigger_tag", new_tags);
2526 
2527 		zbx_db_insert_prepare(&db_insert_ttags, "trigger_tag", "triggertagid", "triggerid", "tag", "value",
2528 				NULL);
2529 	}
2530 
2531 	if (0 != upd_triggers || 0 != upd_functions.values_num || 0 != del_functionids.values_num ||
2532 			0 != del_triggerdepids.values_num || 0 != upd_tags || 0 != del_triggertagids.values_num)
2533 	{
2534 		sql = (char *)zbx_malloc(sql, sql_alloc);
2535 		DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
2536 	}
2537 
2538 	for (i = 0; i < triggers->values_num; i++)
2539 	{
2540 		char	*description_esc, *expression_esc, *comments_esc, *url_esc, *value_esc, *opdata_esc;
2541 		int	index;
2542 
2543 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
2544 
2545 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2546 			continue;
2547 
2548 		index = zbx_vector_ptr_bsearch(trigger_prototypes, &trigger->parent_triggerid,
2549 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2550 
2551 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes->values[index];
2552 
2553 		for (j = 0; j < trigger->functions.values_num; j++)
2554 		{
2555 			function = (zbx_lld_function_t *)trigger->functions.values[j];
2556 
2557 			if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_DELETE))
2558 				continue;
2559 
2560 			if (0 == (function->flags & ZBX_FLAG_LLD_FUNCTION_DISCOVERED))
2561 				continue;
2562 
2563 			if (0 == function->functionid)
2564 			{
2565 				zbx_db_insert_add_values(&db_insert_tfunctions, functionid, function->itemid,
2566 						(0 == trigger->triggerid ? triggerid : trigger->triggerid),
2567 						function->function, function->parameter);
2568 
2569 				function->functionid = functionid++;
2570 			}
2571 		}
2572 
2573 		if (0 == trigger->triggerid || 0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION))
2574 			lld_expression_create(&trigger->expression, &trigger->functions);
2575 
2576 		if (0 == trigger->triggerid || 0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION))
2577 			lld_expression_create(&trigger->recovery_expression, &trigger->functions);
2578 
2579 		if (0 == trigger->triggerid)
2580 		{
2581 			zbx_db_insert_add_values(&db_insert, triggerid, trigger->description, trigger->expression,
2582 					(int)trigger->priority, (int)trigger->status,
2583 					trigger->comments, trigger->url, (int)trigger_prototype->type,
2584 					(int)TRIGGER_VALUE_OK, (int)TRIGGER_STATE_NORMAL,
2585 					(int)ZBX_FLAG_DISCOVERY_CREATED, (int)trigger_prototype->recovery_mode,
2586 					trigger->recovery_expression, (int)trigger_prototype->correlation_mode,
2587 					trigger->correlation_tag, (int)trigger_prototype->manual_close,
2588 					trigger->opdata);
2589 
2590 			zbx_db_insert_add_values(&db_insert_tdiscovery, triggerid, trigger->parent_triggerid);
2591 
2592 			trigger->triggerid = triggerid++;
2593 		}
2594 		else if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE))
2595 		{
2596 			const char	*d = "";
2597 
2598 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update triggers set ");
2599 
2600 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_DESCRIPTION))
2601 			{
2602 				description_esc = DBdyn_escape_string(trigger->description);
2603 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "description='%s'",
2604 						description_esc);
2605 				zbx_free(description_esc);
2606 				d = ",";
2607 			}
2608 
2609 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_EXPRESSION))
2610 			{
2611 				expression_esc = DBdyn_escape_string(trigger->expression);
2612 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sexpression='%s'", d,
2613 						expression_esc);
2614 				zbx_free(expression_esc);
2615 				d = ",";
2616 			}
2617 
2618 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_EXPRESSION))
2619 			{
2620 				expression_esc = DBdyn_escape_string(trigger->recovery_expression);
2621 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%srecovery_expression='%s'", d,
2622 						expression_esc);
2623 				zbx_free(expression_esc);
2624 				d = ",";
2625 			}
2626 
2627 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_RECOVERY_MODE))
2628 			{
2629 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%srecovery_mode=%d", d,
2630 						(int)trigger_prototype->recovery_mode);
2631 				d = ",";
2632 			}
2633 
2634 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_TYPE))
2635 			{
2636 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%stype=%d", d,
2637 						(int)trigger_prototype->type);
2638 				d = ",";
2639 			}
2640 
2641 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_PRIORITY))
2642 			{
2643 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%spriority=%d", d,
2644 						(int)trigger->priority);
2645 				d = ",";
2646 			}
2647 
2648 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_COMMENTS))
2649 			{
2650 				comments_esc = DBdyn_escape_string(trigger->comments);
2651 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scomments='%s'", d, comments_esc);
2652 				zbx_free(comments_esc);
2653 				d = ",";
2654 			}
2655 
2656 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_URL))
2657 			{
2658 				url_esc = DBdyn_escape_string(trigger->url);
2659 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%surl='%s'", d, url_esc);
2660 				zbx_free(url_esc);
2661 				d = ",";
2662 			}
2663 
2664 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_MODE))
2665 			{
2666 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scorrelation_mode=%d", d,
2667 						(int)trigger_prototype->correlation_mode);
2668 				d = ",";
2669 			}
2670 
2671 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_CORRELATION_TAG))
2672 			{
2673 				value_esc = DBdyn_escape_string(trigger->correlation_tag);
2674 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scorrelation_tag='%s'", d,
2675 						value_esc);
2676 				zbx_free(value_esc);
2677 				d = ",";
2678 			}
2679 
2680 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_MANUAL_CLOSE))
2681 			{
2682 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%smanual_close=%d", d,
2683 						(int)trigger_prototype->manual_close);
2684 				d = ",";
2685 			}
2686 
2687 			if (0 != (trigger->flags & ZBX_FLAG_LLD_TRIGGER_UPDATE_OPDATA))
2688 			{
2689 				opdata_esc = DBdyn_escape_string(trigger->opdata);
2690 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sopdata='%s'", d, opdata_esc);
2691 				zbx_free(opdata_esc);
2692 			}
2693 
2694 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2695 					" where triggerid=" ZBX_FS_UI64 ";\n", trigger->triggerid);
2696 		}
2697 	}
2698 
2699 	for (i = 0; i < triggers->values_num; i++)
2700 	{
2701 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
2702 
2703 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2704 			continue;
2705 
2706 		for (j = 0; j < trigger->dependencies.values_num; j++)
2707 		{
2708 			dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
2709 
2710 			if (0 != (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DELETE))
2711 				continue;
2712 
2713 			if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
2714 				continue;
2715 
2716 			if (0 == dependency->triggerdepid)
2717 			{
2718 				triggerid_up = (NULL == dependency->trigger_up ? dependency->triggerid_up :
2719 						dependency->trigger_up->triggerid);
2720 
2721 				zbx_db_insert_add_values(&db_insert_tdepends, triggerdepid, trigger->triggerid,
2722 						triggerid_up);
2723 
2724 				dependency->triggerdepid = triggerdepid++;
2725 			}
2726 		}
2727 	}
2728 
2729 	/* create/update trigger tags */
2730 	for (i = 0; i < triggers->values_num; i++)
2731 	{
2732 		trigger = (zbx_lld_trigger_t *)triggers->values[i];
2733 
2734 		if (0 == (trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED))
2735 			continue;
2736 
2737 		for (j = 0; j < trigger->tags.values_num; j++)
2738 		{
2739 			char	*value_esc;
2740 
2741 			tag = (zbx_lld_tag_t *)trigger->tags.values[j];
2742 
2743 			if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_DELETE))
2744 				continue;
2745 
2746 			if (0 == (tag->flags & ZBX_FLAG_LLD_TAG_DISCOVERED))
2747 				continue;
2748 
2749 			if (0 == tag->triggertagid)
2750 			{
2751 				tag->triggertagid = triggertagid++;
2752 				zbx_db_insert_add_values(&db_insert_ttags, tag->triggertagid, trigger->triggerid,
2753 						tag->tag, tag->value);
2754 			}
2755 			else if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_UPDATE))
2756 			{
2757 				const char	*d = "";
2758 
2759 				zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update trigger_tag set ");
2760 
2761 				if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_UPDATE_TAG))
2762 				{
2763 					value_esc = DBdyn_escape_string(tag->tag);
2764 					zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "tag='%s'", value_esc);
2765 					zbx_free(value_esc);
2766 					d = ",";
2767 				}
2768 
2769 				if (0 != (tag->flags & ZBX_FLAG_LLD_TAG_UPDATE_VALUE))
2770 				{
2771 					value_esc = DBdyn_escape_string(tag->value);
2772 					zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%svalue='%s'", d, value_esc);
2773 					zbx_free(value_esc);
2774 				}
2775 
2776 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2777 						" where triggertagid=" ZBX_FS_UI64 ";\n", tag->triggertagid);
2778 			}
2779 		}
2780 	}
2781 
2782 	zbx_vector_ptr_sort(&upd_functions, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2783 
2784 	for (i = 0; i < upd_functions.values_num; i++)
2785 	{
2786 		const char	*d = "";
2787 
2788 		function = (zbx_lld_function_t *)upd_functions.values[i];
2789 
2790 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update functions set ");
2791 
2792 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_ITEMID))
2793 		{
2794 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "itemid=" ZBX_FS_UI64,
2795 					function->itemid);
2796 			d = ",";
2797 		}
2798 
2799 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_FUNCTION))
2800 		{
2801 			function_esc = DBdyn_escape_string(function->function);
2802 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sname='%s'", d,
2803 					function_esc);
2804 			zbx_free(function_esc);
2805 			d = ",";
2806 		}
2807 
2808 		if (0 != (function->flags & ZBX_FLAG_LLD_FUNCTION_UPDATE_PARAMETER))
2809 		{
2810 			parameter_esc = DBdyn_escape_string(function->parameter);
2811 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sparameter='%s'", d,
2812 					parameter_esc);
2813 			zbx_free(parameter_esc);
2814 		}
2815 
2816 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2817 				" where functionid=" ZBX_FS_UI64 ";\n", function->functionid);
2818 	}
2819 
2820 	if (0 != del_functionids.values_num)
2821 	{
2822 		zbx_vector_uint64_sort(&del_functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2823 
2824 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from functions where");
2825 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "functionid",
2826 				del_functionids.values, del_functionids.values_num);
2827 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2828 	}
2829 
2830 	if (0 != del_triggerdepids.values_num)
2831 	{
2832 		zbx_vector_uint64_sort(&del_triggerdepids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2833 
2834 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from trigger_depends where");
2835 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggerdepid",
2836 				del_triggerdepids.values, del_triggerdepids.values_num);
2837 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2838 	}
2839 
2840 	if (0 != del_triggertagids.values_num)
2841 	{
2842 		zbx_vector_uint64_sort(&del_triggertagids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2843 
2844 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from trigger_tag where");
2845 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggertagid",
2846 				del_triggertagids.values, del_triggertagids.values_num);
2847 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2848 	}
2849 
2850 	if (0 != upd_triggers || 0 != upd_functions.values_num || 0 != del_functionids.values_num ||
2851 			0 != del_triggerdepids.values_num || 0 != upd_tags || 0 != del_triggertagids.values_num)
2852 	{
2853 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
2854 		DBexecute("%s", sql);
2855 		zbx_free(sql);
2856 	}
2857 
2858 	if (0 != new_triggers)
2859 	{
2860 		zbx_db_insert_execute(&db_insert);
2861 		zbx_db_insert_clean(&db_insert);
2862 
2863 		zbx_db_insert_execute(&db_insert_tdiscovery);
2864 		zbx_db_insert_clean(&db_insert_tdiscovery);
2865 	}
2866 
2867 	if (0 != new_functions)
2868 	{
2869 		zbx_db_insert_execute(&db_insert_tfunctions);
2870 		zbx_db_insert_clean(&db_insert_tfunctions);
2871 	}
2872 
2873 	if (0 != new_dependencies)
2874 	{
2875 		zbx_db_insert_execute(&db_insert_tdepends);
2876 		zbx_db_insert_clean(&db_insert_tdepends);
2877 	}
2878 
2879 	if (0 != new_tags)
2880 	{
2881 		zbx_db_insert_execute(&db_insert_ttags);
2882 		zbx_db_insert_clean(&db_insert_ttags);
2883 	}
2884 
2885 	DBcommit();
2886 out:
2887 
2888 	zbx_vector_uint64_destroy(&trigger_protoids);
2889 	zbx_vector_uint64_destroy(&del_triggertagids);
2890 	zbx_vector_uint64_destroy(&del_triggerdepids);
2891 	zbx_vector_uint64_destroy(&del_functionids);
2892 	zbx_vector_ptr_destroy(&upd_functions);
2893 
2894 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2895 
2896 	return ret;
2897 }
2898 
2899 /* hash/comparison functions to support cache/vector lookups by trigger reference */
zbx_lld_trigger_ref_hash_func(const void * data)2900 static zbx_hash_t	zbx_lld_trigger_ref_hash_func(const void *data)
2901 {
2902 	zbx_hash_t			hash;
2903 	const zbx_lld_trigger_node_t	*trigger_node = (const zbx_lld_trigger_node_t *)data;
2904 	void				*ptr = NULL;
2905 
2906 	hash = ZBX_DEFAULT_UINT64_HASH_ALGO(&trigger_node->trigger_ref.triggerid,
2907 			sizeof(trigger_node->trigger_ref.triggerid), ZBX_DEFAULT_HASH_SEED);
2908 
2909 	if (0 == trigger_node->trigger_ref.triggerid)
2910 		ptr = trigger_node->trigger_ref.trigger;
2911 
2912 	return ZBX_DEFAULT_PTR_HASH_ALGO(&ptr, sizeof(trigger_node->trigger_ref.trigger), hash);
2913 }
2914 
zbx_lld_trigger_ref_compare_func(const void * d1,const void * d2)2915 static int	zbx_lld_trigger_ref_compare_func(const void *d1, const void *d2)
2916 {
2917 	const zbx_lld_trigger_node_t	*n1 = (const zbx_lld_trigger_node_t *)d1;
2918 	const zbx_lld_trigger_node_t	*n2 = (const zbx_lld_trigger_node_t *)d2;
2919 
2920 	ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.triggerid, n2->trigger_ref.triggerid);
2921 
2922 	/* Don't check pointer if id matches. If the reference was loaded from database it will not have pointer. */
2923 	if (0 != n1->trigger_ref.triggerid)
2924 		return 0;
2925 
2926 	ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.trigger, n2->trigger_ref.trigger);
2927 
2928 	return 0;
2929 }
2930 
2931 /* comparison function to determine trigger dependency validation order */
zbx_lld_trigger_node_compare_func(const void * d1,const void * d2)2932 static int	zbx_lld_trigger_node_compare_func(const void *d1, const void *d2)
2933 {
2934 	const zbx_lld_trigger_node_t	*n1 = *(const zbx_lld_trigger_node_t **)d1;
2935 	const zbx_lld_trigger_node_t	*n2 = *(const zbx_lld_trigger_node_t **)d2;
2936 
2937 	/* sort in ascending order, but ensure that existing triggers are first */
2938 	if (0 != n1->trigger_ref.triggerid && 0 == n2->trigger_ref.triggerid)
2939 		return -1;
2940 
2941 	/* give priority to nodes with less parents */
2942 	ZBX_RETURN_IF_NOT_EQUAL(n1->parents, n2->parents);
2943 
2944 	/* compare ids */
2945 	ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.triggerid, n2->trigger_ref.triggerid);
2946 
2947 	/* Don't check pointer if id matches. If the reference was loaded from database it will not have pointer. */
2948 	if (0 != n1->trigger_ref.triggerid)
2949 		return 0;
2950 
2951 	ZBX_RETURN_IF_NOT_EQUAL(n1->trigger_ref.trigger, n2->trigger_ref.trigger);
2952 
2953 	return 0;
2954 }
2955 
2956 /******************************************************************************
2957  *                                                                            *
2958  * Function: lld_trigger_cache_append                                         *
2959  *                                                                            *
2960  * Purpose: adds a node to trigger cache                                      *
2961  *                                                                            *
2962  * Parameters: cache     - [IN] the trigger cache                             *
2963  *             triggerid - [IN] the trigger id                                *
2964  *             trigger   - [IN] the trigger data for new triggers             *
2965  *                                                                            *
2966  * Return value: the added node                                               *
2967  *                                                                            *
2968  ******************************************************************************/
lld_trigger_cache_append(zbx_hashset_t * cache,zbx_uint64_t triggerid,zbx_lld_trigger_t * trigger)2969 static zbx_lld_trigger_node_t	*lld_trigger_cache_append(zbx_hashset_t *cache, zbx_uint64_t triggerid,
2970 		zbx_lld_trigger_t *trigger)
2971 {
2972 	zbx_lld_trigger_node_t	node_local;
2973 
2974 	node_local.trigger_ref.triggerid = triggerid;
2975 	node_local.trigger_ref.trigger = trigger;
2976 	node_local.trigger_ref.flags = 0;
2977 	node_local.iter_num = 0;
2978 	node_local.parents = 0;
2979 
2980 	zbx_vector_ptr_create(&node_local.dependencies);
2981 
2982 	return (zbx_lld_trigger_node_t *)zbx_hashset_insert(cache, &node_local, sizeof(node_local));
2983 }
2984 
2985 /******************************************************************************
2986  *                                                                            *
2987  * Function: lld_trigger_cache_add_trigger_node                               *
2988  *                                                                            *
2989  * Purpose: add trigger and all triggers related to it to trigger dependency  *
2990  *          validation cache.                                                 *
2991  *                                                                            *
2992  * Parameters: cache           - [IN] the trigger cache                       *
2993  *             trigger         - [IN] the trigger to add                      *
2994  *             triggerids_up   - [OUT] identifiers of generic trigger         *
2995  *                                     dependents                             *
2996  *             triggerids_down - [OUT] identifiers of generic trigger         *
2997  *                                     dependencies                           *
2998  *                                                                            *
2999  ******************************************************************************/
lld_trigger_cache_add_trigger_node(zbx_hashset_t * cache,zbx_lld_trigger_t * trigger,zbx_vector_uint64_t * triggerids_up,zbx_vector_uint64_t * triggerids_down)3000 static void	lld_trigger_cache_add_trigger_node(zbx_hashset_t *cache, zbx_lld_trigger_t *trigger,
3001 		zbx_vector_uint64_t *triggerids_up, zbx_vector_uint64_t *triggerids_down)
3002 {
3003 	zbx_lld_trigger_ref_t	*trigger_ref;
3004 	zbx_lld_trigger_node_t	*trigger_node, trigger_node_local;
3005 	zbx_lld_dependency_t	*dependency;
3006 	int			i;
3007 
3008 	trigger_node_local.trigger_ref.triggerid = trigger->triggerid;
3009 	trigger_node_local.trigger_ref.trigger = trigger;
3010 
3011 	if (NULL != zbx_hashset_search(cache, &trigger_node_local))
3012 		return;
3013 
3014 	trigger_node = lld_trigger_cache_append(cache, trigger->triggerid, trigger);
3015 
3016 	for (i = 0; i < trigger->dependencies.values_num; i++)
3017 	{
3018 		dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
3019 
3020 		if (0 == (dependency->flags & ZBX_FLAG_LLD_DEPENDENCY_DISCOVERED))
3021 			continue;
3022 
3023 		trigger_ref = (zbx_lld_trigger_ref_t *)zbx_malloc(NULL, sizeof(zbx_lld_trigger_ref_t));
3024 
3025 		trigger_ref->triggerid = dependency->triggerid_up;
3026 		trigger_ref->trigger = dependency->trigger_up;
3027 		trigger_ref->flags = (0 == dependency->triggerdepid ? ZBX_LLD_TRIGGER_DEPENDENCY_NEW :
3028 				ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL);
3029 
3030 		zbx_vector_ptr_append(&trigger_node->dependencies, trigger_ref);
3031 
3032 		if (NULL == trigger_ref->trigger)
3033 		{
3034 			trigger_node_local.trigger_ref.triggerid = trigger_ref->triggerid;
3035 			trigger_node_local.trigger_ref.trigger = NULL;
3036 
3037 			if (NULL == zbx_hashset_search(cache, &trigger_node_local))
3038 			{
3039 				zbx_vector_uint64_append(triggerids_up, trigger_ref->triggerid);
3040 				zbx_vector_uint64_append(triggerids_down, trigger_ref->triggerid);
3041 
3042 				lld_trigger_cache_append(cache, trigger_ref->triggerid, NULL);
3043 			}
3044 		}
3045 	}
3046 
3047 	if (0 != trigger->triggerid)
3048 		zbx_vector_uint64_append(triggerids_up, trigger->triggerid);
3049 
3050 	for (i = 0; i < trigger->dependents.values_num; i++)
3051 	{
3052 		lld_trigger_cache_add_trigger_node(cache, (zbx_lld_trigger_t *)trigger->dependents.values[i], triggerids_up,
3053 				triggerids_down);
3054 	}
3055 
3056 	for (i = 0; i < trigger->dependencies.values_num; i++)
3057 	{
3058 		dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
3059 
3060 		if (NULL != dependency->trigger_up)
3061 		{
3062 			lld_trigger_cache_add_trigger_node(cache, dependency->trigger_up, triggerids_up,
3063 					triggerids_down);
3064 		}
3065 	}
3066 }
3067 
3068 /******************************************************************************
3069  *                                                                            *
3070  * Function: lld_trigger_cache_init                                           *
3071  *                                                                            *
3072  * Purpose: initializes trigger cache used to perform trigger dependency      *
3073  *          validation                                                        *
3074  *                                                                            *
3075  * Parameters: cache    - [IN] the trigger cache                              *
3076  *             triggers - [IN] the discovered triggers                        *
3077  *                                                                            *
3078  * Comments: Triggers with new dependencies and.all triggers related to them  *
3079  *           are added to cache.                                              *
3080  *                                                                            *
3081  ******************************************************************************/
lld_trigger_cache_init(zbx_hashset_t * cache,zbx_vector_ptr_t * triggers)3082 static void	lld_trigger_cache_init(zbx_hashset_t *cache, zbx_vector_ptr_t *triggers)
3083 {
3084 	zbx_vector_uint64_t	triggerids_up, triggerids_down;
3085 	int			i, j;
3086 	char			*sql = NULL;
3087 	size_t			sql_alloc = 0, sql_offset;
3088 	DB_RESULT		result;
3089 	DB_ROW			row;
3090 	zbx_lld_trigger_ref_t	*trigger_ref;
3091 	zbx_lld_trigger_node_t	*trigger_node, trigger_node_local;
3092 
3093 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3094 
3095 	zbx_hashset_create(cache, triggers->values_num, zbx_lld_trigger_ref_hash_func,
3096 			zbx_lld_trigger_ref_compare_func);
3097 
3098 	zbx_vector_uint64_create(&triggerids_down);
3099 	zbx_vector_uint64_create(&triggerids_up);
3100 
3101 	/* add all triggers with new dependencies to trigger cache */
3102 	for (i = 0; i < triggers->values_num; i++)
3103 	{
3104 		zbx_lld_trigger_t	*trigger = (zbx_lld_trigger_t *)triggers->values[i];
3105 
3106 		for (j = 0; j < trigger->dependencies.values_num; j++)
3107 		{
3108 			zbx_lld_dependency_t	*dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[j];
3109 
3110 			if (0 == dependency->triggerdepid)
3111 				break;
3112 		}
3113 
3114 		if (j != trigger->dependencies.values_num)
3115 			lld_trigger_cache_add_trigger_node(cache, trigger, &triggerids_up, &triggerids_down);
3116 	}
3117 
3118 	/* keep trying to load generic dependents/dependencies until there are nothing to load */
3119 	while (0 != triggerids_up.values_num || 0 != triggerids_down.values_num)
3120 	{
3121 		/* load dependents */
3122 		if (0 != triggerids_down.values_num)
3123 		{
3124 			sql_offset = 0;
3125 			zbx_vector_uint64_sort(&triggerids_down, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3126 			zbx_vector_uint64_uniq(&triggerids_down, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3127 
3128 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3129 					"select td.triggerid_down,td.triggerid_up"
3130 					" from trigger_depends td"
3131 						" left join triggers t"
3132 							" on td.triggerid_up=t.triggerid"
3133 					" where t.flags<>%d"
3134 						" and", ZBX_FLAG_DISCOVERY_PROTOTYPE);
3135 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.triggerid_down",
3136 					triggerids_down.values, triggerids_down.values_num);
3137 
3138 			zbx_vector_uint64_clear(&triggerids_down);
3139 
3140 			result = DBselect("%s", sql);
3141 
3142 			while (NULL != (row = DBfetch(result)))
3143 			{
3144 				int			new_node = 0;
3145 				zbx_lld_trigger_node_t	*trigger_node_up;
3146 
3147 				ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[1]);
3148 
3149 				if (NULL == (trigger_node_up = (zbx_lld_trigger_node_t *)zbx_hashset_search(cache, &trigger_node_local)))
3150 				{
3151 					trigger_node_up = lld_trigger_cache_append(cache,
3152 							trigger_node_local.trigger_ref.triggerid, NULL);
3153 					new_node = 1;
3154 				}
3155 
3156 				ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[0]);
3157 
3158 				if (NULL == (trigger_node = (zbx_lld_trigger_node_t *)zbx_hashset_search(cache, &trigger_node_local)))
3159 				{
3160 					THIS_SHOULD_NEVER_HAPPEN;
3161 					continue;
3162 				}
3163 
3164 				/* check if the dependency is not already registered in cache */
3165 				for (i = 0; i < trigger_node->dependencies.values_num; i++)
3166 				{
3167 					trigger_ref = (zbx_lld_trigger_ref_t *)trigger_node->dependencies.values[i];
3168 
3169 					/* references to generic triggers will always have valid id value */
3170 					if (trigger_ref->triggerid == trigger_node_up->trigger_ref.triggerid)
3171 						break;
3172 				}
3173 
3174 				/* if the dependency was not found - add it */
3175 				if (i == trigger_node->dependencies.values_num)
3176 				{
3177 					trigger_ref = (zbx_lld_trigger_ref_t *)zbx_malloc(NULL,
3178 							sizeof(zbx_lld_trigger_ref_t));
3179 
3180 					trigger_ref->triggerid = trigger_node_up->trigger_ref.triggerid;
3181 					trigger_ref->trigger = NULL;
3182 					trigger_ref->flags = ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL;
3183 
3184 					zbx_vector_ptr_append(&trigger_node->dependencies, trigger_ref);
3185 
3186 					trigger_node_up->parents++;
3187 				}
3188 
3189 				if (1 == new_node)
3190 				{
3191 					/* if the trigger was added to cache, we must check its dependencies */
3192 					zbx_vector_uint64_append(&triggerids_up,
3193 							trigger_node_up->trigger_ref.triggerid);
3194 					zbx_vector_uint64_append(&triggerids_down,
3195 							trigger_node_up->trigger_ref.triggerid);
3196 				}
3197 			}
3198 
3199 			DBfree_result(result);
3200 		}
3201 
3202 		/* load dependencies */
3203 		if (0 != triggerids_up.values_num)
3204 		{
3205 			sql_offset = 0;
3206 			zbx_vector_uint64_sort(&triggerids_up, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3207 			zbx_vector_uint64_uniq(&triggerids_up, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3208 
3209 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3210 					"select td.triggerid_down"
3211 					" from trigger_depends td"
3212 						" left join triggers t"
3213 							" on t.triggerid=td.triggerid_down"
3214 					" where t.flags<>%d"
3215 						" and", ZBX_FLAG_DISCOVERY_PROTOTYPE);
3216 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "td.triggerid_up", triggerids_up.values,
3217 					triggerids_up.values_num);
3218 
3219 			zbx_vector_uint64_clear(&triggerids_up);
3220 
3221 			result = DBselect("%s", sql);
3222 
3223 			while (NULL != (row = DBfetch(result)))
3224 			{
3225 				ZBX_STR2UINT64(trigger_node_local.trigger_ref.triggerid, row[0]);
3226 
3227 				if (NULL != zbx_hashset_search(cache, &trigger_node_local))
3228 					continue;
3229 
3230 				lld_trigger_cache_append(cache, trigger_node_local.trigger_ref.triggerid, NULL);
3231 
3232 				zbx_vector_uint64_append(&triggerids_up, trigger_node_local.trigger_ref.triggerid);
3233 				zbx_vector_uint64_append(&triggerids_down, trigger_node_local.trigger_ref.triggerid);
3234 			}
3235 
3236 			DBfree_result(result);
3237 		}
3238 
3239 	}
3240 
3241 	zbx_free(sql);
3242 
3243 	zbx_vector_uint64_destroy(&triggerids_up);
3244 	zbx_vector_uint64_destroy(&triggerids_down);
3245 
3246 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3247 }
3248 
3249 /******************************************************************************
3250  *                                                                            *
3251  * Function: zbx_trigger_cache_clean                                          *
3252  *                                                                            *
3253  * Purpose: releases resources allocated by trigger cache                     *
3254  *          validation                                                        *
3255  *                                                                            *
3256  * Parameters: cache - [IN] the trigger cache                                 *
3257  *                                                                            *
3258  ******************************************************************************/
zbx_trigger_cache_clean(zbx_hashset_t * cache)3259 static void	zbx_trigger_cache_clean(zbx_hashset_t *cache)
3260 {
3261 	zbx_hashset_iter_t	iter;
3262 	zbx_lld_trigger_node_t	*trigger_node;
3263 
3264 	zbx_hashset_iter_reset(cache, &iter);
3265 	while (NULL != (trigger_node = (zbx_lld_trigger_node_t *)zbx_hashset_iter_next(&iter)))
3266 	{
3267 		zbx_vector_ptr_clear_ext(&trigger_node->dependencies, zbx_ptr_free);
3268 		zbx_vector_ptr_destroy(&trigger_node->dependencies);
3269 	}
3270 
3271 	zbx_hashset_destroy(cache);
3272 }
3273 
3274 /******************************************************************************
3275  *                                                                            *
3276  * Function: lld_trigger_dependency_delete                                    *
3277  *                                                                            *
3278  * Purpose: removes trigger dependency                                        *
3279  *                                                                            *
3280  * Parameters: from  - [IN] the reference to dependent trigger                *
3281  *             to    - [IN] the reference to trigger the from depends on      *
3282  *             error - [OUT] the error message                                *
3283  *                                                                            *
3284  * Comments: If possible (the dependency loop was introduced by discovered    *
3285  *           dependencies) the last dependency in the loop will be removed.   *
3286  *           Otherwise (the triggers in database already had dependency loop) *
3287  *           the last dependency in the loop will be marked as removed,       *
3288  *           however the dependency in database will be left intact.          *
3289  *                                                                            *
3290  ******************************************************************************/
lld_trigger_dependency_delete(zbx_lld_trigger_ref_t * from,zbx_lld_trigger_ref_t * to,char ** error)3291 static void	lld_trigger_dependency_delete(zbx_lld_trigger_ref_t *from, zbx_lld_trigger_ref_t *to, char **error)
3292 {
3293 	zbx_lld_trigger_t	*trigger;
3294 	int			i;
3295 	char			*trigger_desc;
3296 
3297 	if (ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL == to->flags)
3298 	{
3299 		/* When old dependency loop has been detected mark it as deleted to avoid   */
3300 		/* infinite recursion during dependency validation, but don't really delete */
3301 		/* it because only new dependencies can be deleted.                         */
3302 
3303 		/* in old dependency loop there are no new triggers, so all involved */
3304 		/* triggers have valid identifiers                                   */
3305 		zabbix_log(LOG_LEVEL_CRIT, "existing recursive dependency loop detected for trigger \""
3306 				ZBX_FS_UI64 "\"", to->triggerid);
3307 		return;
3308 	}
3309 
3310 	trigger = from->trigger;
3311 
3312 	/* remove the dependency */
3313 	for (i = 0; i < trigger->dependencies.values_num; i++)
3314 	{
3315 		zbx_lld_dependency_t	*dependency = (zbx_lld_dependency_t *)trigger->dependencies.values[i];
3316 
3317 		if ((NULL != dependency->trigger_up && dependency->trigger_up == to->trigger) ||
3318 				(0 != dependency->triggerid_up && dependency->triggerid_up == to->triggerid))
3319 		{
3320 			zbx_free(dependency);
3321 			zbx_vector_ptr_remove(&trigger->dependencies, i);
3322 
3323 			break;
3324 		}
3325 	}
3326 
3327 	if (0 != from->triggerid)
3328 		trigger_desc = zbx_dsprintf(NULL, ZBX_FS_UI64, from->triggerid);
3329 	else
3330 		trigger_desc = zbx_strdup(NULL, from->trigger->description);
3331 
3332 	*error = zbx_strdcatf(*error, "Cannot create all trigger \"%s\" dependencies:"
3333 			" recursion too deep.\n", trigger_desc);
3334 
3335 	zbx_free(trigger_desc);
3336 }
3337 
3338 /******************************************************************************
3339  *                                                                            *
3340  * Function: lld_trigger_dependencies_iter                                    *
3341  *                                                                            *
3342  * Purpose: iterates through trigger dependencies to find dependency loops    *
3343  *                                                                            *
3344  * Parameters: cache         - [IN] the trigger cache                         *
3345  *             triggers      - [IN] the discovered triggers                   *
3346  *             trigger_node  - [IN] the trigger to check                      *
3347  *             iter          - [IN] the dependency iterator                   *
3348  *             level         - [IN] the dependency level                      *
3349  *             error         - [OUT] the error message                        *
3350  *                                                                            *
3351  * Return value: SUCCEED - the trigger's dependency chain in valid            *
3352  *               FAIL    - a dependency loop was detected                     *
3353  *                                                                            *
3354  * Comments: If the validation fails the offending dependency is removed.     *
3355  *                                                                            *
3356  ******************************************************************************/
lld_trigger_dependencies_iter(zbx_hashset_t * cache,zbx_vector_ptr_t * triggers,zbx_lld_trigger_node_t * trigger_node,zbx_lld_trigger_node_iter_t * iter,int level,char ** error)3357 static int	lld_trigger_dependencies_iter(zbx_hashset_t *cache, zbx_vector_ptr_t *triggers,
3358 		zbx_lld_trigger_node_t *trigger_node, zbx_lld_trigger_node_iter_t *iter, int level, char **error)
3359 {
3360 	int				i;
3361 	zbx_lld_trigger_ref_t		*trigger_ref;
3362 	zbx_lld_trigger_node_t		*trigger_node_up;
3363 	zbx_lld_trigger_node_iter_t	child_iter, *piter;
3364 
3365 	if (trigger_node->iter_num == iter->iter_num || ZBX_TRIGGER_DEPENDENCY_LEVELS_MAX < level)
3366 	{
3367 		/* dependency loop detected, resolve it by deleting corresponding dependency */
3368 		lld_trigger_dependency_delete(iter->ref_from, iter->ref_to, error);
3369 
3370 		/* mark the dependency as removed */
3371 		iter->ref_to->flags = ZBX_LLD_TRIGGER_DEPENDENCY_DELETE;
3372 
3373 		return FAIL;
3374 	}
3375 
3376 	trigger_node->iter_num = iter->iter_num;
3377 
3378 	for (i = 0; i < trigger_node->dependencies.values_num; i++)
3379 	{
3380 		trigger_ref = (zbx_lld_trigger_ref_t *)trigger_node->dependencies.values[i];
3381 
3382 		/* skip dependencies marked as deleted */
3383 		if (ZBX_LLD_TRIGGER_DEPENDENCY_DELETE == trigger_ref->flags)
3384 			continue;
3385 
3386 		if (NULL == (trigger_node_up = (zbx_lld_trigger_node_t *)zbx_hashset_search(cache, trigger_ref)))
3387 		{
3388 			THIS_SHOULD_NEVER_HAPPEN;
3389 			continue;
3390 		}
3391 
3392 		/* Remember last dependency that could be cut.                         */
3393 		/* It should be either a last new dependency or just a last dependency */
3394 		/* if no new dependencies were encountered.                            */
3395 		if (ZBX_LLD_TRIGGER_DEPENDENCY_NEW == trigger_ref->flags || NULL == iter->ref_to ||
3396 				ZBX_LLD_TRIGGER_DEPENDENCY_NORMAL == iter->ref_to->flags)
3397 		{
3398 			child_iter.ref_from = &trigger_node->trigger_ref;
3399 			child_iter.ref_to = trigger_ref;
3400 			child_iter.iter_num = iter->iter_num;
3401 
3402 			piter = &child_iter;
3403 		}
3404 		else
3405 			piter = iter;
3406 
3407 		if (FAIL == lld_trigger_dependencies_iter(cache, triggers, trigger_node_up, piter, level + 1, error))
3408 			return FAIL;
3409 	}
3410 
3411 	trigger_node->iter_num = 0;
3412 
3413 	return SUCCEED;
3414 }
3415 
3416 /******************************************************************************
3417  *                                                                            *
3418  * Function: lld_trigger_dependencies_validate                                *
3419  *                                                                            *
3420  * Purpose: validate discovered trigger dependencies                          *
3421  *                                                                            *
3422  * Parameters: triggers - [IN] the discovered triggers                        *
3423  *             error    - [OUT] the error message                             *
3424  *             triggers - [IN] the discovered triggers                        *
3425  *             trigger  - [IN] the trigger to check                           *
3426  *             iter     - [IN] the dependency iterator                        *
3427  *             level    - [IN] the dependency level                           *
3428  *                                                                            *
3429  * Comments: During validation the dependency loops will be resolved by       *
3430  *           removing offending dependencies.                                 *
3431  *                                                                            *
3432  ******************************************************************************/
lld_trigger_dependencies_validate(zbx_vector_ptr_t * triggers,char ** error)3433 static void	lld_trigger_dependencies_validate(zbx_vector_ptr_t *triggers, char **error)
3434 {
3435 	zbx_hashset_t			cache;
3436 	zbx_hashset_iter_t		iter;
3437 	zbx_lld_trigger_node_t		*trigger_node, *trigger_node_up;
3438 	zbx_lld_trigger_node_iter_t	node_iter = {0};
3439 	zbx_vector_ptr_t		nodes;
3440 	int				i;
3441 
3442 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3443 
3444 	lld_trigger_cache_init(&cache, triggers);
3445 
3446 	/* Perform dependency validation in the order of trigger ids and starting with parentless triggers. */
3447 	/* This will give some consistency in choosing what dependencies should be deleted in the case of   */
3448 	/* recursion.                                                                                       */
3449 	zbx_vector_ptr_create(&nodes);
3450 	zbx_vector_ptr_reserve(&nodes, cache.num_data);
3451 
3452 	zbx_hashset_iter_reset(&cache, &iter);
3453 	while (NULL != (trigger_node = (zbx_lld_trigger_node_t *)zbx_hashset_iter_next(&iter)))
3454 	{
3455 		for (i = 0; i < trigger_node->dependencies.values_num; i++)
3456 		{
3457 			if (NULL == (trigger_node_up = (zbx_lld_trigger_node_t *)zbx_hashset_search(&cache,
3458 					trigger_node->dependencies.values[i])))
3459 			{
3460 				THIS_SHOULD_NEVER_HAPPEN;
3461 				continue;
3462 			}
3463 
3464 			trigger_node_up->parents++;
3465 		}
3466 		zbx_vector_ptr_append(&nodes, trigger_node);
3467 	}
3468 
3469 	zbx_vector_ptr_sort(&nodes, zbx_lld_trigger_node_compare_func);
3470 
3471 	for (i = 0; i < nodes.values_num; i++)
3472 	{
3473 		if (NULL == (trigger_node = (zbx_lld_trigger_node_t *)zbx_hashset_search(&cache, (zbx_lld_trigger_node_t *)nodes.values[i])))
3474 		{
3475 			THIS_SHOULD_NEVER_HAPPEN;
3476 			continue;
3477 		}
3478 
3479 		/* If dependency iterator returns false it means that dependency loop was detected */
3480 		/* (and resolved). In this case we have to validate dependencies for this trigger  */
3481 		/* again.                                                                          */
3482 		do
3483 		{
3484 			node_iter.iter_num++;
3485 			node_iter.ref_from = NULL;
3486 			node_iter.ref_to = NULL;
3487 		}
3488 		while (SUCCEED != lld_trigger_dependencies_iter(&cache, triggers, trigger_node, &node_iter, 0, error));
3489 	}
3490 
3491 	zbx_vector_ptr_destroy(&nodes);
3492 	zbx_trigger_cache_clean(&cache);
3493 
3494 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3495 }
3496 
get_trigger_info(const void * object,zbx_uint64_t * id,int * discovery_flag,int * lastcheck,int * ts_delete)3497 static	void	get_trigger_info(const void *object, zbx_uint64_t *id, int *discovery_flag, int *lastcheck,
3498 		int *ts_delete)
3499 {
3500 	zbx_lld_trigger_t	*trigger;
3501 
3502 	trigger = (zbx_lld_trigger_t *)object;
3503 
3504 	*id = trigger->triggerid;
3505 	*discovery_flag = trigger->flags & ZBX_FLAG_LLD_TRIGGER_DISCOVERED;
3506 	*lastcheck = trigger->lastcheck;
3507 	*ts_delete = trigger->ts_delete;
3508 }
3509 
3510 /******************************************************************************
3511  *                                                                            *
3512  * Function: lld_update_triggers                                              *
3513  *                                                                            *
3514  * Purpose: add or update triggers for discovered items                       *
3515  *                                                                            *
3516  * Return value: SUCCEED - if triggers were successfully added/updated or     *
3517  *                         adding/updating was not necessary                  *
3518  *               FAIL    - triggers cannot be added/updated                   *
3519  *                                                                            *
3520  ******************************************************************************/
lld_update_triggers(zbx_uint64_t hostid,zbx_uint64_t lld_ruleid,const zbx_vector_ptr_t * lld_rows,const zbx_vector_ptr_t * lld_macro_paths,char ** error,int lifetime,int lastcheck)3521 int	lld_update_triggers(zbx_uint64_t hostid, zbx_uint64_t lld_ruleid, const zbx_vector_ptr_t *lld_rows,
3522 		const zbx_vector_ptr_t *lld_macro_paths, char **error, int lifetime, int lastcheck)
3523 {
3524 	zbx_vector_ptr_t		trigger_prototypes;
3525 	zbx_vector_ptr_t		triggers;
3526 	zbx_vector_ptr_t		items;
3527 	zbx_lld_trigger_t		*trigger;
3528 	zbx_lld_trigger_prototype_t	*trigger_prototype;
3529 	int				ret = SUCCEED, i;
3530 
3531 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3532 
3533 	zbx_vector_ptr_create(&trigger_prototypes);
3534 
3535 	lld_trigger_prototypes_get(lld_ruleid, &trigger_prototypes);
3536 
3537 	if (0 == trigger_prototypes.values_num)
3538 		goto out;
3539 
3540 	zbx_vector_ptr_create(&triggers);	/* list of triggers which were created or will be created or */
3541 						/* updated by the trigger prototype */
3542 	zbx_vector_ptr_create(&items);		/* list of items which are related to the trigger prototypes */
3543 
3544 	lld_triggers_get(&trigger_prototypes, &triggers);
3545 	lld_functions_get(&trigger_prototypes, &triggers);
3546 	lld_dependencies_get(&trigger_prototypes, &triggers);
3547 	lld_tags_get(&trigger_prototypes, &triggers);
3548 	lld_items_get(&trigger_prototypes, &items);
3549 
3550 	/* simplifying trigger expressions */
3551 
3552 	for (i = 0; i < trigger_prototypes.values_num; i++)
3553 	{
3554 		trigger_prototype = (zbx_lld_trigger_prototype_t *)trigger_prototypes.values[i];
3555 
3556 		lld_expressions_simplify(&trigger_prototype->expression, &trigger_prototype->recovery_expression,
3557 				&trigger_prototype->functions);
3558 	}
3559 
3560 	for (i = 0; i < triggers.values_num; i++)
3561 	{
3562 		trigger = (zbx_lld_trigger_t *)triggers.values[i];
3563 
3564 		lld_expressions_simplify(&trigger->expression, &trigger->recovery_expression, &trigger->functions);
3565 	}
3566 
3567 	/* making triggers */
3568 
3569 	lld_triggers_make(&trigger_prototypes, &triggers, &items, lld_rows, lld_macro_paths, error);
3570 	lld_triggers_validate(hostid, &triggers, error);
3571 	lld_trigger_dependencies_make(&trigger_prototypes, &triggers, lld_rows, error);
3572 	lld_trigger_dependencies_validate(&triggers, error);
3573 	lld_trigger_tags_make(&trigger_prototypes, &triggers, lld_rows, lld_macro_paths);
3574 	lld_trigger_tags_validate(&triggers, error);
3575 	ret = lld_triggers_save(hostid, &trigger_prototypes, &triggers);
3576 
3577 	lld_remove_lost_objects("trigger_discovery", "triggerid", &triggers, lifetime, lastcheck, DBdelete_triggers,
3578 			get_trigger_info);
3579 	/* cleaning */
3580 
3581 	zbx_vector_ptr_clear_ext(&items, (zbx_mem_free_func_t)lld_item_free);
3582 	zbx_vector_ptr_clear_ext(&triggers, (zbx_mem_free_func_t)lld_trigger_free);
3583 	zbx_vector_ptr_destroy(&items);
3584 	zbx_vector_ptr_destroy(&triggers);
3585 out:
3586 	zbx_vector_ptr_clear_ext(&trigger_prototypes, (zbx_mem_free_func_t)lld_trigger_prototype_free);
3587 	zbx_vector_ptr_destroy(&trigger_prototypes);
3588 
3589 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3590 
3591 	return ret;
3592 }
3593