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