diff options
Diffstat (limited to 'src/libs/zbxdbwrap/trigger_linking.c')
-rw-r--r-- | src/libs/zbxdbwrap/trigger_linking.c | 1683 |
1 files changed, 1683 insertions, 0 deletions
diff --git a/src/libs/zbxdbwrap/trigger_linking.c b/src/libs/zbxdbwrap/trigger_linking.c new file mode 100644 index 00000000000..e5e0ab153d0 --- /dev/null +++ b/src/libs/zbxdbwrap/trigger_linking.c @@ -0,0 +1,1683 @@ +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#include "trigger_linking.h" +#include "zbxdbwrap.h" +#include "trigger_dep_linking.h" + +#include "zbxeval.h" +#include "log.h" +#include "audit/zbxaudit.h" +#include "audit/zbxaudit_trigger.h" +#include "zbxnum.h" + +typedef struct +{ + zbx_uint64_t hostid; + zbx_uint64_t triggerid; + char *description; + char *expression; + char *recovery_expression; + zbx_uint64_t templateid; + unsigned char flags; + + unsigned char recovery_mode; + unsigned char correlation_mode; + unsigned char manual_close; + char *opdata; + unsigned char discover; + char *event_name; + + unsigned char priority; + char *comments; + char *url; + char *url_name; + char *correlation_tag; + unsigned char status; + unsigned char type; +} +zbx_trigger_copy_t; + +ZBX_PTR_VECTOR_DECL(trigger_copies_templates, zbx_trigger_copy_t *) +ZBX_PTR_VECTOR_IMPL(trigger_copies_templates, zbx_trigger_copy_t *) + +ZBX_PTR_VECTOR_DECL(trigger_copies_insert, zbx_trigger_copy_t *) +ZBX_PTR_VECTOR_IMPL(trigger_copies_insert, zbx_trigger_copy_t *) + +/* TARGET HOST TRIGGER DATA */ +typedef struct +{ + zbx_uint64_t triggerid; + char *description; + char *expression; + char *recovery_expression; + zbx_uint64_t templateid_orig; + zbx_uint64_t templateid; + unsigned char flags; + + unsigned char recovery_mode_orig; + unsigned char recovery_mode; + unsigned char correlation_mode_orig; + unsigned char correlation_mode; + char *correlation_tag_orig; + char *correlation_tag; + unsigned char manual_close_orig; + unsigned char manual_close; + char *opdata_orig; + char *opdata; + unsigned char discover_orig; + unsigned char discover; + char *event_name_orig; + char *event_name; + unsigned char priority_orig; + unsigned char priority; + char *comments_orig; + char *comments; + char *url_orig; + char *url; + char *url_name_orig; + char *url_name; + unsigned char status_orig; + unsigned char status; + unsigned char type_orig; + unsigned char type; + +#define ZBX_FLAG_LINK_TRIGGER_UNSET __UINT64_C(0x00000000) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_RECOVERY_MODE __UINT64_C(0x00000001) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_CORRELATION_MODE __UINT64_C(0x00000002) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_CORRELATION_TAG __UINT64_C(0x00000004) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_MANUAL_CLOSE __UINT64_C(0x00000008) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_OPDATA __UINT64_C(0x00000010) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_DISCOVER __UINT64_C(0x00000020) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_EVENT_NAME __UINT64_C(0x00000040) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_PRIORITY __UINT64_C(0x00000080) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_COMMENTS __UINT64_C(0x00000100) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_URL __UINT64_C(0x00000200) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_TYPE __UINT64_C(0x00000400) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_TEMPLATEID __UINT64_C(0x00000800) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_STATUS __UINT64_C(0x00001000) +#define ZBX_FLAG_LINK_TRIGGER_UPDATE_URL_NAME __UINT64_C(0x00002000) + +#define ZBX_FLAG_LINK_TRIGGER_UPDATE \ + (ZBX_FLAG_LINK_TRIGGER_UPDATE_RECOVERY_MODE | ZBX_FLAG_LINK_TRIGGER_UPDATE_CORRELATION_MODE | \ + ZBX_FLAG_LINK_TRIGGER_UPDATE_CORRELATION_TAG | ZBX_FLAG_LINK_TRIGGER_UPDATE_MANUAL_CLOSE | \ + ZBX_FLAG_LINK_TRIGGER_UPDATE_OPDATA | ZBX_FLAG_LINK_TRIGGER_UPDATE_DISCOVER | \ + ZBX_FLAG_LINK_TRIGGER_UPDATE_EVENT_NAME | ZBX_FLAG_LINK_TRIGGER_UPDATE_PRIORITY | \ + ZBX_FLAG_LINK_TRIGGER_UPDATE_COMMENTS | ZBX_FLAG_LINK_TRIGGER_UPDATE_URL | \ + ZBX_FLAG_LINK_TRIGGER_UPDATE_TYPE | ZBX_FLAG_LINK_TRIGGER_UPDATE_TEMPLATEID | \ + ZBX_FLAG_LINK_TRIGGER_UPDATE_STATUS | ZBX_FLAG_LINK_TRIGGER_UPDATE_URL_NAME) + + zbx_uint64_t update_flags; +} +zbx_target_host_trigger_entry_t; + +ZBX_PTR_VECTOR_DECL(target_host_trigger_data, zbx_target_host_trigger_entry_t *) +ZBX_PTR_VECTOR_IMPL(target_host_trigger_data, zbx_target_host_trigger_entry_t *) + +static zbx_hash_t zbx_host_triggers_main_data_hash_func(const void *data) +{ + const zbx_target_host_trigger_entry_t * trigger_entry = (const zbx_target_host_trigger_entry_t *)data; + + return ZBX_DEFAULT_UINT64_HASH_ALGO(&((trigger_entry)->triggerid), sizeof((trigger_entry)->triggerid), + ZBX_DEFAULT_HASH_SEED); +} + +static int zbx_host_triggers_main_data_compare_func(const void *d1, const void *d2) +{ + const zbx_target_host_trigger_entry_t *trigger_entry_1 = (const zbx_target_host_trigger_entry_t *)d1; + const zbx_target_host_trigger_entry_t *trigger_entry_2 = (const zbx_target_host_trigger_entry_t *)d2; + + ZBX_RETURN_IF_NOT_EQUAL(trigger_entry_1->triggerid, trigger_entry_2->triggerid); + + return 0; +} + +static void zbx_host_triggers_main_data_clean(zbx_hashset_t *h) +{ + zbx_hashset_iter_t iter; + zbx_target_host_trigger_entry_t *trigger_entry; + + zbx_hashset_iter_reset(h, &iter); + + while (NULL != (trigger_entry = (zbx_target_host_trigger_entry_t *)zbx_hashset_iter_next(&iter))) + { + zbx_free(trigger_entry->description); + zbx_free(trigger_entry->expression); + zbx_free(trigger_entry->recovery_expression); + zbx_free(trigger_entry->correlation_tag_orig); + + if (0 != (trigger_entry->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_CORRELATION_TAG)) + zbx_free(trigger_entry->correlation_tag); + + zbx_free(trigger_entry->opdata_orig); + + if (0 != (trigger_entry->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_OPDATA)) + zbx_free(trigger_entry->opdata); + + zbx_free(trigger_entry->event_name_orig); + + if (0 != (trigger_entry->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_EVENT_NAME)) + zbx_free(trigger_entry->event_name); + + zbx_free(trigger_entry->comments_orig); + + if (0 != (trigger_entry->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_COMMENTS)) + zbx_free(trigger_entry->comments); + + zbx_free(trigger_entry->url_orig); + + if (0 != (trigger_entry->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_URL)) + zbx_free(trigger_entry->url); + + zbx_free(trigger_entry->url_name_orig); + + if (0 != (trigger_entry->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_URL_NAME)) + zbx_free(trigger_entry->url_name); + + } + + zbx_hashset_destroy(h); +} + +/* TRIGGER FUNCTIONS DATA */ +typedef struct zbx_trigger_functions_entry +{ + zbx_uint64_t triggerid; + + zbx_vector_str_t functionids; + zbx_vector_uint64_t itemids; + zbx_vector_str_t itemkeys; + zbx_vector_str_t parameters; + zbx_vector_str_t names; + +} zbx_trigger_functions_entry_t; + +static zbx_hash_t zbx_triggers_functions_hash_func(const void *data) +{ + const zbx_trigger_functions_entry_t *trigger_entry = (const zbx_trigger_functions_entry_t *)data; + + return ZBX_DEFAULT_UINT64_HASH_ALGO(&((trigger_entry)->triggerid), sizeof((trigger_entry)->triggerid), + ZBX_DEFAULT_HASH_SEED); +} + +static int zbx_triggers_functions_compare_func(const void *d1, const void *d2) +{ + const zbx_trigger_functions_entry_t *trigger_entry_1 = (const zbx_trigger_functions_entry_t *)d1; + const zbx_trigger_functions_entry_t *trigger_entry_2 = (const zbx_trigger_functions_entry_t *)d2; + + ZBX_RETURN_IF_NOT_EQUAL((trigger_entry_1)->triggerid, (trigger_entry_2)->triggerid); + + return 0; +} + +static void zbx_triggers_functions_clean(zbx_hashset_t *h) +{ + zbx_hashset_iter_t iter; + zbx_trigger_functions_entry_t *trigger_entry; + + zbx_hashset_iter_reset(h, &iter); + + while (NULL != (trigger_entry = (zbx_trigger_functions_entry_t *)zbx_hashset_iter_next(&iter))) + { + zbx_vector_str_clear_ext(&((trigger_entry)->functionids), zbx_str_free); + zbx_vector_str_destroy(&((trigger_entry)->functionids)); + zbx_vector_uint64_destroy(&((trigger_entry)->itemids)); + zbx_vector_str_clear_ext(&((trigger_entry)->itemkeys), zbx_str_free); + zbx_vector_str_destroy(&((trigger_entry)->itemkeys)); + zbx_vector_str_clear_ext(&((trigger_entry)->parameters), zbx_str_free); + zbx_vector_str_destroy(&((trigger_entry)->parameters)); + zbx_vector_str_clear_ext(&((trigger_entry)->names), zbx_str_free); + zbx_vector_str_destroy(&((trigger_entry)->names)); + } + + zbx_hashset_destroy(h); +} + +/* TRIGGER DESCRIPTIONS MAP */ +typedef struct zbx_trigger_descriptions_entry +{ + const char *description; + zbx_vector_uint64_t triggerids; +} zbx_trigger_descriptions_entry_t; + +static zbx_hash_t zbx_triggers_descriptions_hash_func(const void *data) +{ + const zbx_trigger_descriptions_entry_t *trigger_entry = (const zbx_trigger_descriptions_entry_t *)data; + + return ZBX_DEFAULT_STRING_HASH_ALGO(trigger_entry->description, strlen(trigger_entry->description), + ZBX_DEFAULT_HASH_SEED); +} + +static int zbx_triggers_descriptions_compare_func(const void *d1, const void *d2) +{ + const zbx_trigger_descriptions_entry_t *trigger_entry_1 = (const zbx_trigger_descriptions_entry_t *)d1; + const zbx_trigger_descriptions_entry_t *trigger_entry_2 = (const zbx_trigger_descriptions_entry_t *)d2; + + return strcmp((trigger_entry_1)->description, (trigger_entry_2)->description); +} + +static void zbx_triggers_descriptions_clean(zbx_hashset_t *x) +{ + zbx_hashset_iter_t iter; + zbx_trigger_descriptions_entry_t *trigger_entry; + + zbx_hashset_iter_reset(x, &iter); + + while (NULL != (trigger_entry = (zbx_trigger_descriptions_entry_t *)zbx_hashset_iter_next(&iter))) + { + zbx_vector_uint64_destroy(&(trigger_entry->triggerids)); + } + + zbx_hashset_destroy(x); +} + +typedef struct +{ + zbx_uint64_t triggerid; + unsigned char flags; + zbx_vector_db_tag_ptr_t tags; + zbx_vector_db_tag_ptr_t new_tags; +} +zbx_trigger_tags_t; + +ZBX_PTR_VECTOR_DECL(trigger_tags, zbx_trigger_tags_t *) +ZBX_PTR_VECTOR_IMPL(trigger_tags, zbx_trigger_tags_t *) + +static zbx_trigger_tags_t *trigger_tags_create(zbx_uint64_t triggerid, unsigned char flags) +{ + zbx_trigger_tags_t *trigger_tags; + + trigger_tags = (zbx_trigger_tags_t *)zbx_malloc(NULL, sizeof(zbx_trigger_tags_t)); + trigger_tags->triggerid = triggerid; + trigger_tags->flags = flags; + zbx_vector_db_tag_ptr_create(&trigger_tags->tags); + zbx_vector_db_tag_ptr_create(&trigger_tags->new_tags); + + return trigger_tags; +} + +static void trigger_tags_free(zbx_trigger_tags_t *trigger_tags) +{ + zbx_vector_db_tag_ptr_clear_ext(&trigger_tags->tags, zbx_db_tag_free); + zbx_vector_db_tag_ptr_destroy(&trigger_tags->tags); + + zbx_vector_db_tag_ptr_clear_ext(&trigger_tags->new_tags, zbx_db_tag_free); + zbx_vector_db_tag_ptr_destroy(&trigger_tags->new_tags); + + zbx_free(trigger_tags); +} + +/******************************************************************************** + * * + * Purpose: copies tags from template triggers to created/linked triggers * + * * + * Parameters: new_triggerids - the created trigger ids * + * cur_triggerids - the linked trigfer ids * + * * + * Return value: upon successful completion return SUCCEED, or FAIL on DB error * + * * + ********************************************************************************/ +static int DBcopy_template_trigger_tags(const zbx_vector_uint64_t *new_triggerids, + const zbx_vector_uint64_t *cur_triggerids) +{ + DB_RESULT result; + DB_ROW row; + char *sql = NULL; + size_t sql_alloc = 0, sql_offset = 0; + int i, j, ret = SUCCEED, insert_num = 0, update_num = 0, delete_num = 0; + zbx_db_insert_t db_insert; + zbx_vector_uint64_t triggerids, del_tagids; + zbx_vector_trigger_tags_t triggers_tags; + zbx_trigger_tags_t *trigger_tags = NULL; + zbx_uint64_t triggerid, tagid; + zbx_db_tag_t *db_tag; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (0 == new_triggerids->values_num && 0 == cur_triggerids->values_num) + goto out; + + zbx_vector_uint64_create(&triggerids); + zbx_vector_uint64_reserve(&triggerids, (size_t)(new_triggerids->values_num + cur_triggerids->values_num)); + zbx_vector_uint64_append_array(&triggerids, new_triggerids->values, new_triggerids->values_num); + zbx_vector_uint64_append_array(&triggerids, cur_triggerids->values, cur_triggerids->values_num); + zbx_vector_uint64_sort(&triggerids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + zbx_vector_trigger_tags_create(&triggers_tags); + zbx_vector_trigger_tags_reserve(&triggers_tags, (size_t)triggerids.values_alloc); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select tt.triggertagid,t.triggerid,t.flags,tt.tag,tt.value" + " from triggers t" + " left join trigger_tag tt on tt.triggerid=t.triggerid" + " where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.triggerid", triggerids.values, + triggerids.values_num); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by t.triggerid"); + + if (NULL == (result = DBselect("%s", sql))) + { + ret = FAIL; + goto clean; + } + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(triggerid, row[1]); + + if (NULL == trigger_tags || trigger_tags->triggerid != triggerid) + { + unsigned char flags; + + ZBX_STR2UCHAR(flags, row[2]); + trigger_tags = trigger_tags_create(triggerid, flags); + zbx_vector_trigger_tags_append(&triggers_tags, trigger_tags); + } + + if (SUCCEED != DBis_null(row[3])) + { + db_tag = zbx_db_tag_create(row[3], row[4]); + ZBX_DBROW2UINT64(db_tag->tagid, row[0]); + zbx_vector_db_tag_ptr_append(&trigger_tags->tags, db_tag); + } + } + DBfree_result(result); + + sql_offset = 0; + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select t.triggerid,tt.tag,tt.value" + " from trigger_tag tt,triggers t" + " where tt.triggerid=t.templateid" + " and"); + + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "t.triggerid", triggerids.values, triggerids.values_num); + + if (NULL == (result = DBselect("%s", sql))) + { + ret = FAIL; + goto clean; + } + + while (NULL != (row = DBfetch(result))) + { + zbx_trigger_tags_t trigger_tags_local; + + ZBX_STR2UINT64(trigger_tags_local.triggerid, row[0]); + + if (FAIL == (i = zbx_vector_trigger_tags_bsearch(&triggers_tags, &trigger_tags_local, + ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + zbx_vector_db_tag_ptr_append(&triggers_tags.values[i]->new_tags, zbx_db_tag_create(row[1], row[2])); + } + DBfree_result(result); + + for (i = 0; i < triggers_tags.values_num; i++) + { + trigger_tags = triggers_tags.values[i]; + (void)zbx_merge_tags(&trigger_tags->tags, &trigger_tags->new_tags, NULL, NULL); + + for (j = 0; j < trigger_tags->tags.values_num; j++) + { + db_tag = trigger_tags->tags.values[j]; + + if (0 == db_tag->tagid) + insert_num++; + else if (0 != (db_tag->flags & ZBX_FLAG_DB_TAG_UPDATE)) + update_num++; + else if (0 != (db_tag->flags & ZBX_FLAG_DB_TAG_REMOVE)) + delete_num++; + } + } + + if (0 == insert_num && 0 == update_num && 0 == delete_num) + goto clean; + + if (0 != update_num) + { + sql_offset = 0; + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + } + + if (0 != insert_num) + { + zbx_db_insert_prepare(&db_insert, "trigger_tag", "triggertagid", "triggerid", "tag", "value", NULL); + tagid = DBget_maxid_num("trigger_tag", insert_num); + } + + if (0 != delete_num) + { + zbx_vector_uint64_create(&del_tagids); + zbx_vector_uint64_reserve(&del_tagids, (size_t)delete_num); + } + + for (i = 0; i < triggers_tags.values_num; i++) + { + trigger_tags = triggers_tags.values[i]; + + for (j = 0; j < trigger_tags->tags.values_num; j++) + { + const char *d = ""; + + db_tag = trigger_tags->tags.values[j]; + + if (0 == db_tag->tagid) + { + zbx_db_insert_add_values(&db_insert, tagid, trigger_tags->triggerid, + db_tag->tag, db_tag->value); + + zbx_audit_trigger_update_json_add_tags_and_values(trigger_tags->triggerid, + trigger_tags->flags, tagid, db_tag->tag, db_tag->value); + + tagid++; + } + else if (0 != (db_tag->flags & ZBX_FLAG_DB_TAG_UPDATE)) + { + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update trigger_tag set "); + + zbx_audit_trigger_update_json_update_trigger_tag_create_entry(trigger_tags->triggerid, + trigger_tags->flags, db_tag->tagid); + + if (0 != (db_tag->flags & ZBX_FLAG_DB_TAG_UPDATE_TAG)) + { + char *tag_esc; + + tag_esc = DBdyn_escape_string(db_tag->tag); + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%stag='%s'", d, tag_esc); + + d = ","; + zbx_free(tag_esc); + + zbx_audit_trigger_update_json_update_tag_tag(trigger_tags->triggerid, + trigger_tags->flags, db_tag->tagid, db_tag->tag_orig, + db_tag->tag); + + } + + if (0 != (db_tag->flags & ZBX_FLAG_DB_TAG_UPDATE_VALUE)) + { + char *value_esc; + + value_esc = DBdyn_escape_string(db_tag->value); + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%svalue='%s'", d, value_esc); + zbx_free(value_esc); + + zbx_audit_trigger_update_json_update_tag_value(trigger_tags->triggerid, + trigger_tags->flags, db_tag->tagid, db_tag->value_orig, + db_tag->value); + } + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where triggertagid=" ZBX_FS_UI64 + ";\n", db_tag->tagid); + + DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset); + } + else if (0 != (db_tag->flags & ZBX_FLAG_DB_TAG_REMOVE)) + { + zbx_vector_uint64_append(&del_tagids, db_tag->tagid); + + zbx_audit_trigger_update_json_delete_tags(trigger_tags->triggerid, trigger_tags->flags, + db_tag->tagid); + } + } + } + + if (0 != update_num) + { + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + if (16 < sql_offset) /* in ORACLE always present begin..end; */ + DBexecute("%s", sql); + } + + if (0 != insert_num) + { + zbx_db_insert_execute(&db_insert); + zbx_db_insert_clean(&db_insert); + } + + if (0 != delete_num) + { + zbx_vector_uint64_sort(&del_tagids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + sql_offset = 0; + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "delete from trigger_tag where"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "triggertagid", del_tagids.values, + del_tagids.values_num); + DBexecute("%s", sql); + + zbx_vector_uint64_destroy(&del_tagids); + } + +clean: + zbx_free(sql); + zbx_vector_uint64_destroy(&triggerids); + + zbx_vector_trigger_tags_clear_ext(&triggers_tags, trigger_tags_free); + zbx_vector_trigger_tags_destroy(&triggers_tags); + +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +static int get_trigger_funcs(zbx_vector_uint64_t *triggerids, zbx_hashset_t *funcs_res) +{ + char *sql = NULL; + size_t sql_alloc = 256, sql_offset = 0; + int res = SUCCEED; + DB_RESULT result; + DB_ROW row; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (0 == triggerids->values_num) + goto end; + + sql = (char *)zbx_malloc(sql, sql_alloc); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select f.triggerid,f.functionid,f.parameter,i.itemid,i.key_,f.name" + " from functions f,items i" + " where i.itemid=f.itemid" + " and"); + + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "f.triggerid", triggerids->values, + triggerids->values_num); + + if (NULL == (result = DBselect("%s", sql))) + { + res = FAIL; + goto clean; + } + + while (NULL != (row = DBfetch(result))) + { + zbx_trigger_functions_entry_t *found, temp_t; + zbx_uint64_t itemid_temp_var; + + ZBX_STR2UINT64(temp_t.triggerid, row[0]); + ZBX_STR2UINT64(itemid_temp_var, row[3]); + + if (NULL != (found = (zbx_trigger_functions_entry_t *)zbx_hashset_search(funcs_res, + &temp_t))) + { + zbx_vector_str_append(&(found->functionids), zbx_strdup(NULL, row[1])); + zbx_vector_uint64_append(&(found->itemids), itemid_temp_var); + zbx_vector_str_append(&(found->itemkeys), zbx_strdup(NULL, row[4])); + zbx_vector_str_append(&(found->parameters), zbx_strdup(NULL, row[2])); + zbx_vector_str_append(&(found->names), zbx_strdup(NULL, row[5])); + } + else + { + zbx_trigger_functions_entry_t local_temp_t; + + zbx_vector_str_create(&(local_temp_t.functionids)); + zbx_vector_uint64_create(&(local_temp_t.itemids)); + zbx_vector_str_create(&(local_temp_t.itemkeys)); + + /* we definitely do need names, when comparing triggers expressions for identity */ + zbx_vector_str_create(&(local_temp_t.names)); + zbx_vector_str_create(&(local_temp_t.parameters)); + + zbx_vector_str_append(&(local_temp_t.functionids), zbx_strdup(NULL, row[1])); + zbx_vector_uint64_append(&(local_temp_t.itemids), itemid_temp_var); + zbx_vector_str_append(&(local_temp_t.itemkeys), zbx_strdup(NULL, row[4])); + zbx_vector_str_append(&(local_temp_t.parameters), zbx_strdup(NULL, row[2])); + zbx_vector_str_append(&(local_temp_t.names), zbx_strdup(NULL, row[5])); + + local_temp_t.triggerid = temp_t.triggerid; + zbx_hashset_insert(funcs_res, &local_temp_t, sizeof(local_temp_t)); + } + } +clean: + zbx_free(sql); + DBfree_result(result); +end: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +static int get_templates_triggers_data(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids, + zbx_vector_trigger_copies_templates_t *trigger_copies_templates, + zbx_vector_str_t *templates_triggers_descriptions, zbx_vector_uint64_t *temp_templates_triggerids) +{ + char *sql = NULL; + size_t sql_alloc = 512, sql_offset = 0; + int res = SUCCEED; + zbx_trigger_copy_t *trigger_copy; + DB_RESULT result; + DB_ROW row; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, + "select t.triggerid,t.description,t.expression,t.status," + "t.type,t.priority,t.comments,t.url,t.url_name,t.flags,t.recovery_expression,t.recovery_mode," + "t.correlation_mode,t.correlation_tag,t.manual_close,t.opdata,t.discover,t.event_name" + " from triggers t" + " where t.triggerid in (select distinct tg.triggerid" + " from triggers tg,functions f,items i" + " where tg.triggerid=f.triggerid" + " and f.itemid=i.itemid" + " and"); + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "i.hostid", templateids->values, templateids->values_num); + zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')'); + + if (NULL == (result = DBselect("%s", sql))) + { + res = FAIL; + goto clean; + } + + while (NULL != (row = DBfetch(result))) + { + trigger_copy = (zbx_trigger_copy_t *)zbx_malloc(NULL, sizeof(zbx_trigger_copy_t)); + trigger_copy->hostid = hostid; + ZBX_STR2UINT64(trigger_copy->triggerid, row[0]); + trigger_copy->description = zbx_strdup(NULL, row[1]); + trigger_copy->expression = zbx_strdup(NULL, row[2]); + trigger_copy->recovery_expression = zbx_strdup(NULL, row[10]); + trigger_copy->templateid = trigger_copy->triggerid; + trigger_copy->flags = (unsigned char)atoi(row[9]); + + trigger_copy->recovery_mode = (unsigned char)atoi(row[11]); + trigger_copy->correlation_tag = zbx_strdup(NULL, row[13]); + trigger_copy->manual_close = (unsigned char)atoi(row[14]); + trigger_copy->opdata = zbx_strdup(NULL, row[15]); + trigger_copy->discover = (unsigned char)atoi(row[16]); + trigger_copy->event_name = zbx_strdup(NULL, row[17]); + + trigger_copy->priority = (unsigned char)atoi(row[5]); + trigger_copy->comments = zbx_strdup(NULL, row[6]); + trigger_copy->url = zbx_strdup(NULL, row[7]); + trigger_copy->url_name = zbx_strdup(NULL, row[8]); + trigger_copy->correlation_mode = (unsigned char)atoi(row[12]); + trigger_copy->status = (unsigned char)atoi(row[3]); + trigger_copy->type = (unsigned char)atoi(row[4]); + + zbx_vector_trigger_copies_templates_append(trigger_copies_templates, trigger_copy); + zbx_vector_str_append(templates_triggers_descriptions, zbx_strdup(NULL, trigger_copy->description)); + zbx_vector_uint64_append(temp_templates_triggerids, trigger_copy->triggerid); + } +clean: + zbx_free(sql); + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +static int get_target_host_main_data(zbx_uint64_t hostid, zbx_vector_str_t *templates_triggers_descriptions, + zbx_hashset_t *zbx_host_triggers_main_data, zbx_vector_uint64_t *temp_host_triggerids, + zbx_hashset_t *triggers_descriptions) +{ + char *sql = NULL; + size_t sql_alloc = 256, sql_offset = 0; + int res = SUCCEED; + DB_RESULT result; + DB_ROW row; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + sql = (char *)zbx_malloc(sql, sql_alloc); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "select t.triggerid,t.description,t.expression,t.recovery_expression" + ",t.flags,t.recovery_mode,t.correlation_mode,t.correlation_tag,t.manual_close,t.opdata" + ",t.discover,t.event_name,t.priority,t.comments,t.url,t.url_name,t.templateid,t.type,t.status" + " from triggers t" + " where t.triggerid in (select distinct tg.triggerid" + " from triggers tg,functions f,items i" + " where tg.triggerid=f.triggerid" + " and f.itemid=i.itemid" + " and tg.templateid is null" + " and i.hostid=" ZBX_FS_UI64 + " and", hostid); + + DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "tg.description", + (const char **)templates_triggers_descriptions->values, + templates_triggers_descriptions->values_num); + zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')'); + + if (NULL == (result = DBselect("%s", sql))) + { + res = FAIL; + goto clean; + } + + while (NULL != (row = DBfetch(result))) + { + zbx_target_host_trigger_entry_t target_host_trigger_entry; + zbx_trigger_descriptions_entry_t *found, temp_t; + + target_host_trigger_entry.update_flags = ZBX_FLAG_LINK_TRIGGER_UNSET; + + ZBX_STR2UINT64(target_host_trigger_entry.triggerid, row[0]); + target_host_trigger_entry.description = zbx_strdup(NULL, row[1]); + target_host_trigger_entry.expression = zbx_strdup(NULL, row[2]); + target_host_trigger_entry.recovery_expression = zbx_strdup(NULL, row[3]); + ZBX_DBROW2UINT64(target_host_trigger_entry.templateid_orig, row[16]); + target_host_trigger_entry.templateid = 0; + ZBX_STR2UINT64(target_host_trigger_entry.flags, row[4]); + + ZBX_STR2UCHAR(target_host_trigger_entry.recovery_mode_orig, row[5]); + target_host_trigger_entry.recovery_mode = 0; + ZBX_STR2UCHAR(target_host_trigger_entry.correlation_mode_orig, row[6]); + target_host_trigger_entry.correlation_mode = 0; + target_host_trigger_entry.correlation_tag_orig = zbx_strdup(NULL, row[7]); + target_host_trigger_entry.correlation_tag = NULL; + ZBX_STR2UCHAR(target_host_trigger_entry.manual_close_orig, row[8]); + target_host_trigger_entry.manual_close = 0; + target_host_trigger_entry.opdata_orig = zbx_strdup(NULL, row[9]); + target_host_trigger_entry.opdata = NULL; + ZBX_STR2UCHAR(target_host_trigger_entry.discover_orig, row[10]); + target_host_trigger_entry.discover = 0; + target_host_trigger_entry.event_name_orig = zbx_strdup(NULL, row[11]); + target_host_trigger_entry.event_name = NULL; + ZBX_STR2UCHAR(target_host_trigger_entry.priority_orig, row[12]); + target_host_trigger_entry.priority = 0; + target_host_trigger_entry.comments_orig = zbx_strdup(NULL, row[13]); + target_host_trigger_entry.comments = NULL; + target_host_trigger_entry.url_orig = zbx_strdup(NULL, row[14]); + target_host_trigger_entry.url = NULL; + target_host_trigger_entry.url_name_orig = zbx_strdup(NULL, row[15]); + target_host_trigger_entry.url_name = NULL; + ZBX_STR2UCHAR(target_host_trigger_entry.type_orig, row[17]); + target_host_trigger_entry.type = 0; + ZBX_STR2UCHAR(target_host_trigger_entry.status_orig, row[18]); + target_host_trigger_entry.status = 0; + + zbx_hashset_insert(zbx_host_triggers_main_data, &target_host_trigger_entry, + sizeof(target_host_trigger_entry)); + zbx_vector_uint64_append(temp_host_triggerids, target_host_trigger_entry.triggerid); + temp_t.description = target_host_trigger_entry.description; + + if (NULL != (found = (zbx_trigger_descriptions_entry_t *)zbx_hashset_search( + triggers_descriptions, &temp_t))) + { + zbx_vector_uint64_append(&(found->triggerids), target_host_trigger_entry.triggerid); + } + else + { + zbx_trigger_descriptions_entry_t local_temp_t; + + zbx_vector_uint64_create(&(local_temp_t.triggerids)); + local_temp_t.description = target_host_trigger_entry.description; + zbx_vector_uint64_append(&(local_temp_t.triggerids), target_host_trigger_entry.triggerid); + zbx_hashset_insert(triggers_descriptions, &local_temp_t, sizeof(local_temp_t)); + } + } +clean: + zbx_free(sql); + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +static int compare_triggers(zbx_trigger_copy_t * template_trigger, zbx_target_host_trigger_entry_t *main_found, + zbx_hashset_t *zbx_templates_triggers_funcs, zbx_hashset_t *zbx_host_triggers_funcs) +{ + int i, j, ret = FAIL; + char *expr, *rexpr, *old_expr, search[MAX_ID_LEN + 3], replace[MAX_ID_LEN + 3]; + zbx_trigger_functions_entry_t *found_template_trigger_funcs, temp_t_template_trigger_funcs, + *found_host_trigger_funcs, temp_t_host_trigger_funcs; + + expr = zbx_strdup(NULL, main_found->expression); + rexpr = zbx_strdup(NULL, main_found->recovery_expression); + + temp_t_template_trigger_funcs.triggerid = template_trigger->triggerid; + temp_t_host_trigger_funcs.triggerid = main_found->triggerid; + + if (NULL != (found_template_trigger_funcs = (zbx_trigger_functions_entry_t *)zbx_hashset_search( + zbx_templates_triggers_funcs, &temp_t_template_trigger_funcs)) && + NULL != (found_host_trigger_funcs = (zbx_trigger_functions_entry_t *) + zbx_hashset_search(zbx_host_triggers_funcs, + &temp_t_host_trigger_funcs))) + { + for (i = 0; i < found_template_trigger_funcs->functionids.values_num; i++) + { + char *itemkeys_value = found_template_trigger_funcs->itemkeys.values[i]; + char *parameters_value = found_template_trigger_funcs->parameters.values[i]; + char *names_value = found_template_trigger_funcs->names.values[i]; + char *functionid = found_template_trigger_funcs->functionids.values[i]; + + for (j = 0; j < found_host_trigger_funcs->functionids.values_num; j++) + { + if (0 == strcmp(itemkeys_value, found_host_trigger_funcs->itemkeys.values[j]) && + 0 == strcmp(parameters_value, + found_host_trigger_funcs->parameters.values[j]) && + 0 == strcmp(names_value, found_host_trigger_funcs->names.values[j])) + { + zbx_snprintf(search, sizeof(search), "{%s}", + found_host_trigger_funcs->functionids.values[j]); + zbx_snprintf(replace, sizeof(replace), "{%s}", functionid); + + old_expr = expr; + expr = zbx_string_replace(expr, search, replace); + zbx_free(old_expr); + + old_expr = rexpr; + rexpr = zbx_string_replace(rexpr, search, replace); + zbx_free(old_expr); + } + } + } + } + + if (0 != strcmp(template_trigger->expression, expr) || 0 != strcmp(template_trigger->recovery_expression, + rexpr)) + { + goto out; + } + + ret = SUCCEED; +out: + zbx_free(rexpr); + zbx_free(expr); + + return ret; +} + +static void mark_updates_for_host_trigger(zbx_trigger_copy_t *trigger_copy, + zbx_target_host_trigger_entry_t *main_found) +{ + if (trigger_copy->recovery_mode != main_found->recovery_mode_orig) + { + main_found->recovery_mode = trigger_copy->recovery_mode; + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_RECOVERY_MODE; + } + + if (trigger_copy->correlation_mode != main_found->correlation_mode_orig) + { + main_found->correlation_mode = trigger_copy->correlation_mode; + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_CORRELATION_MODE; + } + + if (0 != strcmp(trigger_copy->correlation_tag, main_found->correlation_tag_orig)) + { + main_found->correlation_tag = zbx_strdup(NULL, trigger_copy->correlation_tag); + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_CORRELATION_TAG; + } + + if (trigger_copy->manual_close != main_found->manual_close_orig) + { + main_found->manual_close = trigger_copy->manual_close; + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_MANUAL_CLOSE; + } + + if (0 != strcmp(trigger_copy->opdata, main_found->opdata_orig)) + { + main_found->opdata = zbx_strdup(NULL, trigger_copy->opdata); + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_OPDATA; + } + + if (trigger_copy->discover != main_found->discover_orig) + { + main_found->discover = trigger_copy->discover; + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_DISCOVER; + } + + if (0 != strcmp(trigger_copy->event_name, main_found->event_name_orig)) + { + main_found->event_name = zbx_strdup(NULL, trigger_copy->event_name); + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_EVENT_NAME; + } + + if (trigger_copy->priority != main_found->priority_orig) + { + main_found->priority = trigger_copy->priority; + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_PRIORITY; + } + + if (0 != strcmp(trigger_copy->comments, main_found->comments_orig)) + { + main_found->comments = zbx_strdup(NULL, trigger_copy->comments); + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_COMMENTS; + } + + if (0 != strcmp(trigger_copy->url, main_found->url_orig)) + { + main_found->url = zbx_strdup(NULL, trigger_copy->url); + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_URL; + } + + if (0 != strcmp(trigger_copy->url_name, main_found->url_name_orig)) + { + main_found->url_name = zbx_strdup(NULL, trigger_copy->url_name); + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_URL_NAME; + } + + if (trigger_copy->type != main_found->type_orig) + { + main_found->type = trigger_copy->type; + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_TYPE; + } + + if (trigger_copy->status != main_found->status_orig) + { + main_found->status = trigger_copy->status; + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_STATUS; + } + + main_found->templateid = trigger_copy->triggerid; + main_found->update_flags |= ZBX_FLAG_LINK_TRIGGER_UPDATE_TEMPLATEID; +} + +static int execute_triggers_updates(zbx_hashset_t *zbx_host_triggers_main_data) +{ + int res = SUCCEED; + const char *d; + char *sql = NULL; + size_t sql_alloc = 512, sql_offset = 0; + zbx_hashset_iter_t iter1; + zbx_target_host_trigger_entry_t *found; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_hashset_iter_reset(zbx_host_triggers_main_data, &iter1); + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + while (NULL != (found = (zbx_target_host_trigger_entry_t *)zbx_hashset_iter_next(&iter1))) + { + d = ""; + + zbx_audit_trigger_create_entry(ZBX_AUDIT_ACTION_UPDATE, found->triggerid, found->description, + (int)found->flags); + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE)) + { + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update triggers set "); + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_RECOVERY_MODE)) + { + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%srecovery_mode=%d", d, + found->recovery_mode); + d = ","; + + zbx_audit_trigger_update_json_update_recovery_mode(found->triggerid, + (int)found->flags, found->recovery_mode_orig, + found->recovery_mode); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_CORRELATION_MODE)) + { + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scorrelation_mode=%d", d, + found->correlation_mode); + d = ","; + + zbx_audit_trigger_update_json_update_correlation_mode(found->triggerid, + (int)found->flags, found->correlation_mode_orig, + found->correlation_mode); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_CORRELATION_TAG)) + { + char *correlation_tag_esc = DBdyn_escape_string(found->correlation_tag); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scorrelation_tag='%s'", d, + correlation_tag_esc); + zbx_free(correlation_tag_esc); + d = ","; + + zbx_audit_trigger_update_json_update_correlation_tag(found->triggerid, + (int)found->flags, found->correlation_tag_orig, found->correlation_tag); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_MANUAL_CLOSE)) + { + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%smanual_close=%d", d, + found->manual_close); + d = ","; + + zbx_audit_trigger_update_json_update_manual_close(found->triggerid, (int)found->flags, + found->manual_close_orig, found->manual_close); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_OPDATA)) + { + char *opdata_esc = DBdyn_escape_string(found->opdata); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sopdata='%s'", d, opdata_esc); + zbx_free(opdata_esc); + d = ","; + + zbx_audit_trigger_update_json_update_opdata(found->triggerid, (int)found->flags, + found->opdata_orig, found->opdata); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_DISCOVER)) + { + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sdiscover=%d", d, found->discover); + d = ","; + + zbx_audit_trigger_update_json_update_discover(found->triggerid, + (int)found->flags, found->discover_orig, found->discover); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_EVENT_NAME)) + { + char *event_name_esc = DBdyn_escape_string(found->event_name); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sevent_name='%s'", d, + event_name_esc); + d = ","; + zbx_free(event_name_esc); + + zbx_audit_trigger_update_json_update_event_name(found->triggerid, + (int)found->flags, found->event_name_orig, found->event_name); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_PRIORITY)) + { + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%spriority=%d", d, found->priority); + d = ","; + + zbx_audit_trigger_update_json_update_priority(found->triggerid, + (int)found->flags, found->priority_orig, found->priority); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_COMMENTS)) + { + char *comments_esc = DBdyn_escape_string(found->comments); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%scomments='%s'", d, + comments_esc); + d = ","; + zbx_free(comments_esc); + + zbx_audit_trigger_update_json_update_comments(found->triggerid, + (int)found->flags, found->comments_orig, found->comments); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_URL)) + { + char *url_esc = DBdyn_escape_string(found->url); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%surl='%s'", d, + url_esc); + d = ","; + zbx_free(url_esc); + + zbx_audit_trigger_update_json_update_url(found->triggerid, + (int)found->flags, found->url_orig, found->url); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_URL_NAME)) + { + char *url_name_esc = DBdyn_escape_string(found->url_name); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%surl_name='%s'", d, + url_name_esc); + d = ","; + zbx_free(url_name_esc); + + zbx_audit_trigger_update_json_update_url_name(found->triggerid, + (int)found->flags, found->url_name_orig, found->url_name); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_TYPE)) + { + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%stype='%d'", d, + found->type); + d = ","; + + zbx_audit_trigger_update_json_update_type(found->triggerid, + (int)found->flags, found->type_orig, found->type); + } + + if (0 != (found->update_flags & ZBX_FLAG_LINK_TRIGGER_UPDATE_STATUS)) + { + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%sstatus='%d'", d, + found->status); + d = ","; + + zbx_audit_trigger_update_json_update_status(found->triggerid, + (int)found->flags, found->status_orig, found->status); + } + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%stemplateid=" ZBX_FS_UI64, d, + found->templateid); + + zbx_audit_trigger_update_json_update_templateid(found->triggerid, (int)found->flags, + found->templateid_orig, found->templateid); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where triggerid=" ZBX_FS_UI64 ";\n", + found->triggerid); + + if (FAIL == DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset)) + { + res = FAIL; + goto clean; + } + } + } + + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + if (16 < sql_offset) + { + if (ZBX_DB_OK > DBexecute("%s", sql)) + res = FAIL; + } +clean: + zbx_free(sql); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +static int get_funcs_for_insert(zbx_uint64_t hostid, zbx_vector_uint64_t *insert_templateid_triggerids, + zbx_hashset_t *zbx_insert_triggers_funcs, int *funcs_insert_count) +{ + int res = SUCCEED; + char *sql = NULL; + size_t sql_alloc = 512, sql_offset = 0; + DB_RESULT result; + DB_ROW row; + zbx_uint64_t itemid; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (0 == insert_templateid_triggerids->values_num) + goto out; + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + " select hi.itemid,tf.functionid,tf.name,tf.parameter,ti.key_,tf.triggerid" + " from functions tf,items ti" + " left join items hi" + " on hi.key_=ti.key_" + " and hi.hostid=" ZBX_FS_UI64 + " where tf.itemid=ti.itemid" + " and", hostid); + + DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "tf.triggerid", insert_templateid_triggerids->values, + insert_templateid_triggerids->values_num); + + if (NULL == (result = DBselect("%s", sql))) + { + res = FAIL; + goto clean; + } + + while (SUCCEED == res && NULL != (row = DBfetch(result))) + { + zbx_trigger_functions_entry_t *found, temp_t; + + if (SUCCEED != DBis_null(row[0])) + { + ZBX_STR2UINT64(itemid, row[0]); + ZBX_STR2UINT64(temp_t.triggerid, row[5]); + + if (NULL != (found = (zbx_trigger_functions_entry_t *)zbx_hashset_search( + zbx_insert_triggers_funcs, &temp_t))) + { + zbx_vector_uint64_append(&(found->itemids), itemid); + zbx_vector_str_append(&(found->functionids), zbx_strdup(NULL, row[1])); + zbx_vector_str_append(&(found->itemkeys), zbx_strdup(NULL, row[4])); + zbx_vector_str_append(&(found->names), zbx_strdup(NULL, row[2])); + zbx_vector_str_append(&(found->parameters), zbx_strdup(NULL, row[3])); + } + else + { + zbx_trigger_functions_entry_t local_temp_t; + + zbx_vector_str_create(&(local_temp_t.functionids)); + zbx_vector_uint64_create(&(local_temp_t.itemids)); + zbx_vector_str_create(&(local_temp_t.itemkeys)); + zbx_vector_str_create(&(local_temp_t.names)); + zbx_vector_str_create(&(local_temp_t.parameters)); + + zbx_vector_uint64_append(&(local_temp_t.itemids), itemid); + zbx_vector_str_append(&(local_temp_t.functionids), zbx_strdup(NULL, row[1])); + zbx_vector_str_append(&(local_temp_t.itemkeys), zbx_strdup(NULL, row[4])); + zbx_vector_str_append(&(local_temp_t.names),zbx_strdup(NULL, row[2])); + zbx_vector_str_append(&(local_temp_t.parameters), zbx_strdup(NULL, row[3])); + + local_temp_t.triggerid = temp_t.triggerid; + + zbx_hashset_insert(zbx_insert_triggers_funcs, &local_temp_t, sizeof(local_temp_t)); + } + + (*funcs_insert_count)++; + } + else + res = FAIL; + } +clean: + zbx_free(sql); + DBfree_result(result); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +static int execute_triggers_inserts(zbx_vector_trigger_copies_insert_t *trigger_copies_insert, + zbx_hashset_t *zbx_insert_triggers_funcs, zbx_vector_uint64_t *new_triggerids, int *funcs_insert_count, + char **error) +{ + int i, j, res; + char *sql_update_triggers_expr = NULL; + size_t sql_update_triggers_expr_alloc = 512, sql_update_triggers_expr_offset = 0; + zbx_uint64_t triggerid, triggerid2, functionid; + zbx_db_insert_t db_insert, db_insert_funcs; + zbx_trigger_functions_entry_t *found, temp_t; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_DBbegin_multiple_update(&sql_update_triggers_expr, &sql_update_triggers_expr_alloc, + &sql_update_triggers_expr_offset); + + zbx_db_insert_prepare(&db_insert, "triggers", "triggerid", "description", "priority", "status", "comments", + "url", "url_name", "type", "value", "state", "templateid", "flags", "recovery_mode", "correlation_mode", + "correlation_tag", "manual_close", "opdata", "discover", "event_name", NULL); + + zbx_db_insert_prepare(&db_insert_funcs, "functions", "functionid", "itemid", "triggerid", "name", + "parameter", NULL); + + triggerid = triggerid2 = DBget_maxid_num("triggers", trigger_copies_insert->values_num); + functionid = DBget_maxid_num("functions", *funcs_insert_count); + + for (i = 0; i < trigger_copies_insert->values_num; i++) + { + zbx_trigger_copy_t *trigger_copy_template = trigger_copies_insert->values[i]; + + zbx_db_insert_add_values(&db_insert, triggerid, trigger_copy_template->description, + (int)trigger_copy_template->priority, (int)trigger_copy_template->status, + trigger_copy_template->comments, trigger_copy_template->url, + trigger_copy_template->url_name, (int)trigger_copy_template->type, TRIGGER_VALUE_OK, + TRIGGER_STATE_NORMAL, trigger_copy_template->templateid, + (int)trigger_copy_template->flags, (int)trigger_copy_template->recovery_mode, + (int)trigger_copy_template->correlation_mode, trigger_copy_template->correlation_tag, + (int)trigger_copy_template->manual_close, trigger_copy_template->opdata, + trigger_copy_template->discover, trigger_copy_template->event_name); + + zbx_vector_uint64_append(new_triggerids, triggerid); + + zbx_audit_trigger_create_entry(ZBX_AUDIT_ACTION_ADD, triggerid, trigger_copy_template->description, + (int)trigger_copy_template->flags); + zbx_audit_trigger_update_json_add_data(triggerid, trigger_copy_template->templateid, + trigger_copy_template->recovery_mode, trigger_copy_template->status, + trigger_copy_template->type, TRIGGER_VALUE_OK, TRIGGER_STATE_NORMAL, + trigger_copy_template->priority, trigger_copy_template->comments, + trigger_copy_template->url, trigger_copy_template->url_name, + trigger_copy_template->flags, trigger_copy_template->correlation_mode, + trigger_copy_template->correlation_tag, trigger_copy_template->manual_close, + trigger_copy_template->opdata, trigger_copy_template->discover, + trigger_copy_template->event_name); + + triggerid++; + } + + res = zbx_db_insert_execute(&db_insert); + zbx_db_insert_clean(&db_insert); + + for (i = 0; res == SUCCEED && i < trigger_copies_insert->values_num; i++) + { + zbx_eval_context_t ctx, ctx_r; + zbx_trigger_copy_t *trigger_copy_template = trigger_copies_insert->values[i]; + zbx_uint64_t parse_rules = ZBX_EVAL_PARSE_TRIGGER_EXPRESSION | ZBX_EVAL_COMPOSE_FUNCTIONID; + + if (0 != (trigger_copy_template->flags & ZBX_FLAG_DISCOVERY_PROTOTYPE)) + parse_rules |= ZBX_EVAL_PARSE_LLDMACRO | ZBX_EVAL_COMPOSE_LLD; + + if (SUCCEED != (res = zbx_eval_parse_expression(&ctx, trigger_copy_template->expression, parse_rules, + error))) + { + goto func_out; + } + + if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == (int)trigger_copy_template->recovery_mode && + (SUCCEED != (res = zbx_eval_parse_expression(&ctx_r, + trigger_copy_template->recovery_expression, parse_rules, error)))) + { + zbx_eval_clear(&ctx); + goto func_out; + } + + temp_t.triggerid = trigger_copy_template->templateid; + + if (NULL != (found = (zbx_trigger_functions_entry_t *)zbx_hashset_search(zbx_insert_triggers_funcs, + &temp_t))) + { + for (j = 0; j < found->functionids.values_num; j++) + { + zbx_uint64_t old_functionid; + + ZBX_DBROW2UINT64(old_functionid, found->functionids.values[j]); + zbx_eval_replace_functionid(&ctx, old_functionid, functionid); + + if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == + (int)trigger_copy_template->recovery_mode) + { + zbx_eval_replace_functionid(&ctx_r, old_functionid, functionid); + } + + zbx_db_insert_add_values(&db_insert_funcs, functionid++, + found->itemids.values[j], triggerid2, found->names.values[j], + found->parameters.values[j]); + } + } + + if (SUCCEED == (res = zbx_eval_validate_replaced_functionids(&ctx, error)) && + TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == (int)trigger_copy_template->recovery_mode) + { + res = zbx_eval_validate_replaced_functionids(&ctx_r, error); + } + + if (SUCCEED == res) + { + char *new_expression = NULL, *esc; + + zbx_eval_compose_expression(&ctx, &new_expression); + esc = DBdyn_escape_field("triggers", "expression", new_expression); + zbx_snprintf_alloc(&sql_update_triggers_expr, &sql_update_triggers_expr_alloc, + &sql_update_triggers_expr_offset, + "update triggers set expression='%s'", esc); + + /* technically this is an update SQL operation, but logically it is an add, so we audit it */ + /* as such */ + zbx_audit_trigger_update_json_add_expr(triggerid2, trigger_copy_template->flags, + new_expression); + + zbx_free(esc); + zbx_free(new_expression); + + if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == (int)trigger_copy_template->recovery_mode) + { + zbx_eval_compose_expression(&ctx_r, &new_expression); + esc = DBdyn_escape_field("triggers", "recovery_expression", new_expression); + zbx_snprintf_alloc(&sql_update_triggers_expr, + &sql_update_triggers_expr_alloc, &sql_update_triggers_expr_offset, + ",recovery_expression='%s'", esc); + + zbx_audit_trigger_update_json_add_rexpr(triggerid2, trigger_copy_template->flags, + new_expression); + + zbx_free(esc); + zbx_free(new_expression); + } + + zbx_snprintf_alloc(&sql_update_triggers_expr, &sql_update_triggers_expr_alloc, + &sql_update_triggers_expr_offset, + " where triggerid=" ZBX_FS_UI64 ";\n", + triggerid2); + + if (FAIL == DBexecute_overflowed_sql(&sql_update_triggers_expr, &sql_update_triggers_expr_alloc, + &sql_update_triggers_expr_offset)) + { + res = FAIL; + } + } + + zbx_eval_clear(&ctx); + + if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == (int)trigger_copy_template->recovery_mode) + zbx_eval_clear(&ctx_r); +func_out: + triggerid2++; + } + + if (SUCCEED == res) + res = zbx_db_insert_execute(&db_insert_funcs); + zbx_db_insert_clean(&db_insert_funcs); + + zbx_DBend_multiple_update(&sql_update_triggers_expr, &sql_update_triggers_expr_alloc, + &sql_update_triggers_expr_offset); + + if (SUCCEED == res && 16 < sql_update_triggers_expr_offset) /* In ORACLE always present begin..end; */ + { + if (ZBX_DB_OK > DBexecute("%s", sql_update_triggers_expr)) + res = FAIL; + } + + zbx_free(sql_update_triggers_expr); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} + +static void process_triggers(zbx_trigger_copy_t *trigger_copy_template, zbx_hashset_t *host_triggers_descriptions, + zbx_hashset_t *zbx_host_triggers_main_data, zbx_hashset_t *zbx_templates_triggers_funcs, + zbx_hashset_t *zbx_host_triggers_funcs, int *upd_triggers, zbx_vector_uint64_t *cur_triggerids, + zbx_vector_trigger_copies_insert_t *trigger_copies_insert, + zbx_vector_uint64_t *insert_templateid_triggerids) +{ + int j, found_descriptions_match = FAIL; + zbx_trigger_descriptions_entry_t *found, temp_t; + + temp_t.description = trigger_copy_template->description; + + if (NULL != (found = (zbx_trigger_descriptions_entry_t *)zbx_hashset_search( + host_triggers_descriptions, &temp_t))) + { + for (j = 0; j < found->triggerids.values_num; j++) + { + zbx_target_host_trigger_entry_t main_temp_t, *main_found; + + main_temp_t.triggerid = found->triggerids.values[j]; + + if (NULL != (main_found = (zbx_target_host_trigger_entry_t *)zbx_hashset_search( + zbx_host_triggers_main_data, &main_temp_t)) && + SUCCEED == compare_triggers(trigger_copy_template, main_found, + zbx_templates_triggers_funcs, zbx_host_triggers_funcs)) + { + found_descriptions_match = SUCCEED; + + mark_updates_for_host_trigger(trigger_copy_template, main_found); + (*upd_triggers)++; + zbx_vector_uint64_append(cur_triggerids, found->triggerids.values[j]); + + break; + } + } + } + + /* not found any entries on host with the same description, expression and recovery expression, so insert it */ + if (FAIL == found_descriptions_match) + { + zbx_trigger_copy_t *trigger_copy_insert; + + /* save data for trigger */ + trigger_copy_insert = (zbx_trigger_copy_t *)zbx_malloc(NULL, sizeof(zbx_trigger_copy_t)); + trigger_copy_insert->description = zbx_strdup(NULL, trigger_copy_template->description); + trigger_copy_insert->expression= zbx_strdup(NULL, trigger_copy_template->expression); + trigger_copy_insert->recovery_expression= zbx_strdup(NULL, + trigger_copy_template->recovery_expression); + trigger_copy_insert->templateid = trigger_copy_template->triggerid; + trigger_copy_insert->flags = trigger_copy_template->flags; + + trigger_copy_insert->recovery_mode = trigger_copy_template->recovery_mode; + trigger_copy_insert->correlation_mode = trigger_copy_template->correlation_mode; + trigger_copy_insert->manual_close = trigger_copy_template->manual_close; + trigger_copy_insert->opdata = zbx_strdup(NULL, trigger_copy_template->opdata); + trigger_copy_insert->discover = trigger_copy_template->discover; + trigger_copy_insert->event_name = zbx_strdup(NULL, trigger_copy_template->event_name); + + trigger_copy_insert->priority = trigger_copy_template->priority; + trigger_copy_insert->comments = zbx_strdup(NULL, trigger_copy_template->comments); + trigger_copy_insert->url = zbx_strdup(NULL, trigger_copy_template->url); + trigger_copy_insert->url_name = zbx_strdup(NULL, trigger_copy_template->url_name); + trigger_copy_insert->correlation_tag = zbx_strdup(NULL, trigger_copy_template->correlation_tag); + trigger_copy_insert->status = trigger_copy_template->status; + trigger_copy_insert->type = trigger_copy_template->type; + + zbx_vector_trigger_copies_insert_append(trigger_copies_insert, trigger_copy_insert); + zbx_vector_uint64_append(insert_templateid_triggerids, trigger_copy_template->triggerid); + } +} + +static void trigger_copies_free(zbx_trigger_copy_t *trigger_copy) +{ + zbx_free(trigger_copy->comments); + zbx_free(trigger_copy->url); + zbx_free(trigger_copy->url_name); + zbx_free(trigger_copy->expression); + zbx_free(trigger_copy->recovery_expression); + zbx_free(trigger_copy->event_name); + zbx_free(trigger_copy->correlation_tag); + zbx_free(trigger_copy->description); + zbx_free(trigger_copy->opdata); + zbx_free(trigger_copy); +} + +/******************************************************************************** + * * + * Purpose: Copy template triggers to host * + * * + * Parameters: hostid - [IN] host identifier from database * + * templateids - [IN] array of template IDs * + * error - [IN] the error message * + * * + * Return value: upon successful completion return SUCCEED, or FAIL on DB error * + * * + * Comments: !!! Don't forget to sync the code with PHP !!! * + * * + ********************************************************************************/ +int DBcopy_template_triggers(zbx_uint64_t hostid, const zbx_vector_uint64_t *templateids, char **error) +{ + int i, upd_triggers = 0, funcs_insert_count = 0, res = SUCCEED; + zbx_vector_uint64_t new_triggerids, cur_triggerids; + zbx_vector_trigger_copies_templates_t trigger_copies_templates; + zbx_vector_trigger_copies_insert_t trigger_copies_insert; + zbx_vector_str_t templates_triggers_descriptions; + zbx_vector_uint64_t temp_templates_triggerids, temp_host_triggerids, + insert_templateid_triggerids; + zbx_hashset_t zbx_templates_triggers_funcs, zbx_host_triggers_funcs, + zbx_host_triggers_main_data, host_triggers_descriptions, + zbx_insert_triggers_funcs; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_uint64_create(&new_triggerids); + zbx_vector_uint64_create(&cur_triggerids); + zbx_vector_uint64_create(&insert_templateid_triggerids); + zbx_vector_uint64_create(&temp_templates_triggerids); + zbx_vector_uint64_create(&temp_host_triggerids); + zbx_vector_str_create(&templates_triggers_descriptions); + zbx_vector_trigger_copies_insert_create(&trigger_copies_insert); + zbx_vector_trigger_copies_templates_create(&trigger_copies_templates); +#define TRIGGER_FUNCS_HASHSET_DEF_SIZE 100 + zbx_hashset_create(&host_triggers_descriptions, TRIGGER_FUNCS_HASHSET_DEF_SIZE, + zbx_triggers_descriptions_hash_func, + zbx_triggers_descriptions_compare_func); + zbx_hashset_create(&zbx_templates_triggers_funcs, TRIGGER_FUNCS_HASHSET_DEF_SIZE, + zbx_triggers_functions_hash_func, + zbx_triggers_functions_compare_func); + zbx_hashset_create(&zbx_host_triggers_funcs, TRIGGER_FUNCS_HASHSET_DEF_SIZE, + zbx_triggers_functions_hash_func, + zbx_triggers_functions_compare_func); + zbx_hashset_create(&zbx_host_triggers_main_data, TRIGGER_FUNCS_HASHSET_DEF_SIZE, + zbx_host_triggers_main_data_hash_func, + zbx_host_triggers_main_data_compare_func); + zbx_hashset_create(&zbx_insert_triggers_funcs, TRIGGER_FUNCS_HASHSET_DEF_SIZE, + zbx_triggers_functions_hash_func, + zbx_triggers_functions_compare_func); +#undef TRIGGER_FUNCS_HASHSET_DEF_SIZE + res = get_templates_triggers_data(hostid, templateids, &trigger_copies_templates, + &templates_triggers_descriptions, &temp_templates_triggerids); + + if (0 == templates_triggers_descriptions.values_num) + goto end; + + if (SUCCEED == res) + { + res = get_target_host_main_data(hostid, &templates_triggers_descriptions, &zbx_host_triggers_main_data, + &temp_host_triggerids, &host_triggers_descriptions); + } + + if (SUCCEED == res) + res = get_trigger_funcs(&temp_templates_triggerids, &zbx_templates_triggers_funcs); + + if (SUCCEED == res) + res = get_trigger_funcs(&temp_host_triggerids, &zbx_host_triggers_funcs); + + if (SUCCEED == res) + { + for (i = 0; i < trigger_copies_templates.values_num; i++) + { + process_triggers(trigger_copies_templates.values[i], &host_triggers_descriptions, + &zbx_host_triggers_main_data, &zbx_templates_triggers_funcs, + &zbx_host_triggers_funcs, &upd_triggers, &cur_triggerids, + &trigger_copies_insert, &insert_templateid_triggerids); + } + } + + if (SUCCEED == res) + { + res = get_funcs_for_insert(hostid, &insert_templateid_triggerids, &zbx_insert_triggers_funcs, + &funcs_insert_count); + } + + if (SUCCEED == res && 0 < upd_triggers) + res = execute_triggers_updates(&zbx_host_triggers_main_data); + + if (SUCCEED == res && 0 < trigger_copies_insert.values_num) + { + res = execute_triggers_inserts(&trigger_copies_insert, &zbx_insert_triggers_funcs, + &new_triggerids, &funcs_insert_count, error); + } + + if (SUCCEED == res) + { + res = DBsync_template_dependencies_for_triggers(hostid, &temp_host_triggerids, + TRIGGER_DEP_SYNC_UPDATE_OP); + } + + if (SUCCEED == res) + res = DBsync_template_dependencies_for_triggers(hostid, &new_triggerids, TRIGGER_DEP_SYNC_INSERT_OP); + + if (SUCCEED == res) + res = DBcopy_template_trigger_tags(&new_triggerids, &cur_triggerids); + + if (FAIL == res && NULL == *error) + *error = zbx_strdup(NULL, "unknown error while linking triggers"); +end: + zbx_vector_uint64_destroy(&new_triggerids); + zbx_vector_uint64_destroy(&cur_triggerids); + zbx_vector_uint64_destroy(&insert_templateid_triggerids); + zbx_vector_uint64_destroy(&temp_templates_triggerids); + zbx_vector_uint64_destroy(&temp_host_triggerids); + zbx_vector_str_clear_ext(&templates_triggers_descriptions, zbx_str_free); + zbx_vector_str_destroy(&templates_triggers_descriptions); + zbx_vector_trigger_copies_templates_clear_ext(&trigger_copies_templates, trigger_copies_free); + zbx_vector_trigger_copies_templates_destroy(&trigger_copies_templates); + zbx_vector_trigger_copies_insert_clear_ext(&trigger_copies_insert, trigger_copies_free); + zbx_vector_trigger_copies_insert_destroy(&trigger_copies_insert); + zbx_triggers_descriptions_clean(&host_triggers_descriptions); + zbx_host_triggers_main_data_clean(&zbx_host_triggers_main_data); + zbx_triggers_functions_clean(&zbx_insert_triggers_funcs); + zbx_triggers_functions_clean(&zbx_templates_triggers_funcs); + zbx_triggers_functions_clean(&zbx_host_triggers_funcs); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(res)); + + return res; +} |