diff options
author | Alexander Shubin <aleksandrs.subins@zabbix.com> | 2021-05-10 17:49:31 +0300 |
---|---|---|
committer | Alexander Shubin <aleksandrs.subins@zabbix.com> | 2021-05-10 17:49:31 +0300 |
commit | 6884c1c7a2e9debd41f149f168b87250a249c0c6 (patch) | |
tree | 4dafc24a5ee5c70d3dc808eede06d8bf09768c43 /src | |
parent | 1ca32e7b027871a26432c1b9d2a5883740bd6231 (diff) | |
parent | afed3e3c3669bec757c1b5eb92968f87ea1c9278 (diff) |
A...I..... [ZBXNEXT-6411] updated to latest from master; resolved conflicts in:
# create/src/schema.tmpl
# src/libs/zbxdbupgrade/dbupgrade_5030.c
# templates/app/activemq_jmx/template_app_activemq_jmx.yaml
# templates/app/apache_agent/template_app_apache_agent.yaml
# templates/app/apache_http/template_app_apache_http.yaml
# templates/app/aranet/aranet_cloud.yaml
# templates/app/ceph_agent2/template_app_ceph_agent2.yaml
# templates/app/docker/template_app_docker.yaml
# templates/app/elasticsearch_http/template_app_elasticsearch_http.yaml
# templates/app/etcd_http/template_app_etcd_http.yaml
# templates/app/exchange/template_app_exchange.yaml
# templates/app/exchange_active/template_app_exchange_active.yaml
# templates/app/generic_java_jmx/template_app_generic_java_jmx.yaml
# templates/app/gitlab_http/template_app_gitlab_http.yaml
# templates/app/hadoop_http/template_app_hadoop_http.yaml
# templates/app/haproxy_agent/template_app_haproxy_agent.yaml
# templates/app/haproxy_http/template_app_haproxy_http.yaml
# templates/app/iis_agent/template_app_iis_agent.yaml
# templates/app/iis_agent_active/template_app_iis_agent_active.yaml
# templates/app/jenkins/template_app_jenkins.yaml
# templates/app/kafka_jmx/template_app_kafka_jmx.yaml
# templates/app/memcached/template_app_memcached.yaml
# templates/app/nginx_agent/template_app_nginx_agent.yaml
# templates/app/nginx_http/template_app_nginx_http.yaml
# templates/app/php-fpm_agent/template_app_php-fpm_agent.yaml
# templates/app/php-fpm_http/template_app_php-fpm_http.yaml
# templates/app/rabbitmq_agent/template_app_rabbitmq_agent.yaml
# templates/app/rabbitmq_http/template_app_rabbitmq_http.yaml
# templates/app/sharepoint_http/template_app_sharepoint_http.yaml
# templates/app/squid_snmp/template_app_squid_snmp.yaml
# templates/app/tomcat_jmx/template_app_tomcat_jmx.yaml
# templates/app/vault_http/template_app_vault.yaml
# templates/app/vmware/template_app_vmware.yaml
# templates/app/vmware_fqdn/template_app_vmware_fqdn.yaml
# templates/app/wildfly_domain_jmx/template_app_wildfly_domain_jmx.yaml
# templates/app/wildfly_server_jmx/template_app_wildfly_server_jmx.yaml
# templates/app/zookeeper_http/template_app_zookeeper_http.yaml
# templates/cctv/hikvision/template_cctv_hikvision_camera.yaml
# templates/classic/template_app_ftp_service.yaml
# templates/classic/template_app_http_service.yaml
# templates/classic/template_app_https_service.yaml
# templates/classic/template_app_imap_service.yaml
# templates/classic/template_app_ldap_service.yaml
# templates/classic/template_app_nntp_service.yaml
# templates/classic/template_app_ntp_service.yaml
# templates/classic/template_app_pop_service.yaml
# templates/classic/template_app_remote_zabbix_proxy.yaml
# templates/classic/template_app_remote_zabbix_server.yaml
# templates/classic/template_app_smtp_service.yaml
# templates/classic/template_app_ssh_service.yaml
# templates/classic/template_app_telnet_service.yaml
# templates/classic/template_app_zabbix_proxy.yaml
# templates/classic/template_app_zabbix_server.yaml
# templates/classic/template_os_aix.yaml
# templates/classic/template_os_freebsd.yaml
# templates/classic/template_os_hp-ux.yaml
# templates/classic/template_os_mac_os_x.yaml
# templates/classic/template_os_openbsd.yaml
# templates/classic/template_os_solaris.yaml
# templates/classic/template_server_intel_sr1530_ipmi.yaml
# templates/classic/template_server_intel_sr1630_ipmi.yaml
# templates/db/cassandra_jmx/template_db_cassandra_jmx.yaml
# templates/db/clickhouse_http/template_db_clickhouse_http.yaml
# templates/db/ignite_jmx/template_db_ignite_jmx.yaml
# templates/db/mongodb/template_db_mongodb.yaml
# templates/db/mongodb_cluster/template_db_mongodb_cluster.yaml
# templates/db/mssql_odbc/template_db_mssql_odbc.yaml
# templates/db/mysql_agent/template_db_mysql_agent.yaml
# templates/db/mysql_agent2/template_db_mysql_agent2.yaml
# templates/db/mysql_odbc/template_db_mysql_odbc.yaml
# templates/db/oracle_agent2/template_db_oracle_agent2.yaml
# templates/db/oracle_odbc/template_db_oracle_odbc.yaml
# templates/db/postgresql/template_db_postgresql.yaml
# templates/db/postgresql_agent2/template_db_postgresql_agent2.yaml
# templates/db/redis/template_db_redis.yaml
# templates/db/tidb_http/tidb_pd_http/template_db_tidb_pd_http.yaml
# templates/db/tidb_http/tidb_tidb_http/template_db_tidb_tidb_http.yaml
# templates/db/tidb_http/tidb_tikv_http/template_db_tidb_tikv_http.yaml
# templates/module/00icmp_ping/00template_module_icmp_ping.yaml
# templates/module/ether_like_snmp/template_module_ether_like_snmp.yaml
# templates/module/generic_snmp_snmp/template_module_generic_snmp_snmp.yaml
# templates/module/host_resources_snmp/template_module_host_resources_snmp.yaml
# templates/module/interfaces_simple_snmp/template_module_interfaces_simple_snmp.yaml
# templates/module/interfaces_snmp/template_module_interfaces_snmp.yaml
# templates/module/interfaces_win_snmp/template_module_interfaces_win_snmp.yaml
# templates/module/smart_agent2/template_module_smart_agent2.yaml
# templates/module/smart_agent2_active/template_module_smart_agent2_active.yaml
# templates/module/zabbix_agent/template_module_zabbix_agent.yaml
# templates/net/alcatel_timetra_snmp/template_net_alcatel_timetra_snmp.yaml
# templates/net/arista_snmp/template_net_arista_snmp.yaml
# templates/net/brocade_fc_sw_snmp/template_net_brocade_fc_sw_snmp.yaml
# templates/net/brocade_foundry_sw_snmp/template_net_brocade_foundry_sw_snmp.yaml
# templates/net/cisco_catalyst_3750/cisco_catalyst_3750_24fs_snmp/template_net_cisco_catalyst_3750_24fs_snmp.yaml
# templates/net/cisco_catalyst_3750/cisco_catalyst_3750_24ps_snmp/template_net_cisco_catalyst_3750_24ps_snmp.yaml
# templates/net/cisco_catalyst_3750/cisco_catalyst_3750_24ts_snmp/template_net_cisco_catalyst_3750_24ts_snmp.yaml
# templates/net/cisco_catalyst_3750/cisco_catalyst_3750_48ps_snmp/template_net_cisco_catalyst_3750_48ps_snmp.yaml
# templates/net/cisco_catalyst_3750/cisco_catalyst_3750_48ts_snmp/template_net_cisco_catalyst_3750_48ts_snmp.yaml
# templates/net/cisco_snmp/template_net_cisco_snmp.yaml
# templates/net/dell_force_s_series_snmp/template_net_dell_force_s_series_snmp.yaml
# templates/net/dlink_des7200_snmp/template_net_dlink_des7200_snmp.yaml
# templates/net/dlink_des_snmp/template_net_dlink_des_snmp.yaml
# templates/net/extreme_snmp/template_net_extreme_snmp.yaml
# templates/net/hp_hh3c_snmp/template_net_hp_hh3c_snmp.yaml
# templates/net/hp_hpn_snmp/template_net_hp_hpn_snmp.yaml
# templates/net/huawei_snmp/template_net_huawei_snmp.yaml
# templates/net/intel_qlogic_infiniband_snmp/template_net_intel_qlogic_infiniband_snmp.yaml
# templates/net/juniper_snmp/template_net_juniper_snmp.yaml
# templates/net/mellanox_snmp/template_net_mellanox_snmp.yaml
# templates/net/mikrotik_snmp/template_net_mikrotik_snmp.yaml
# templates/net/morningstar_snmp/prostar_mppt_snmp/prostar_mppt_snmp.yaml
# templates/net/morningstar_snmp/prostar_pwm_snmp/prostar_pwm_snmp.yaml
# templates/net/morningstar_snmp/sunsaver_mppt_snmp/sunsaver_mppt_snmp.yaml
# templates/net/morningstar_snmp/suresine_snmp/suresine_snmp.yaml
# templates/net/morningstar_snmp/tristar_mppt_600V_snmp/tristar_mppt_600V_snmp.yaml
# templates/net/morningstar_snmp/tristar_mppt_snmp/tristar_mppt_snmp.yaml
# templates/net/morningstar_snmp/tristar_pwm_snmp/tristar_pwm_snmp.yaml
# templates/net/netgear_snmp/template_net_netgear_snmp.yaml
# templates/net/qtech_snmp/template_net_qtech_snmp.yaml
# templates/net/tplink_snmp/template_net_tplink_snmp.yaml
# templates/net/ubiquiti_airos_snmp/template_net_ubiquiti_airos_snmp.yaml
# templates/os/linux/template_os_linux.yaml
# templates/os/linux_active/template_os_linux_active.yaml
# templates/os/linux_prom/template_os_linux_prom.yaml
# templates/os/linux_snmp_snmp/template_os_linux_snmp_snmp.yaml
# templates/os/windows_agent/template_os_windows_agent.yaml
# templates/os/windows_agent_active/template_os_windows_agent_active.yaml
# templates/power/apc/apc_ups_galaxy_3500_snmp/template_power_apc_ups_galaxy_3500_snmp.yaml
# templates/power/apc/apc_ups_smart_2200_rm_snmp/template_power_apc_ups_smart_2200_rm_snmp.yaml
# templates/power/apc/apc_ups_smart_3000_xlm_snmp/template_power_apc_ups_smart_3000_xlm_snmp.yaml
# templates/power/apc/apc_ups_smart_rt_1000_rm_xl_snmp/template_power_apc_ups_smart_rt_1000_rm_xl_snmp.yaml
# templates/power/apc/apc_ups_smart_rt_1000_xl_snmp/template_power_apc_ups_smart_rt_1000_xl_snmp.yaml
# templates/power/apc/apc_ups_smart_srt_5000_snmp/template_power_apc_ups_smart_srt_5000_snmp.yaml
# templates/power/apc/apc_ups_smart_srt_8000_snmp/template_power_apc_ups_smart_srt_8000_snmp.yaml
# templates/power/apc/apc_ups_snmp/template_power_apc_ups_snmp.yaml
# templates/power/apc/apc_ups_symmetra_lx_snmp/template_power_apc_ups_symmetra_lx_snmp.yaml
# templates/power/apc/apc_ups_symmetra_rm_snmp/template_power_apc_ups_symmetra_rm_snmp.yaml
# templates/power/apc/apc_ups_symmetra_rx_snmp/template_power_apc_ups_symmetra_rx_snmp.yaml
# templates/san/huawei_5300v5_snmp/template_san_huawei_5300v5_snmp.yaml
# templates/san/netapp_aff_a700_http/template_san_netapp_aff_a700_http.yaml
# templates/san/netapp_fas3220_snmp/template_san_netapp_fas3220_snmp.yaml
# templates/server/chassis_ipmi/template_server_chassis_ipmi.yaml
# templates/server/cisco_ucs_snmp/template_server_cisco_ucs_snmp.yaml
# templates/server/dell_idrac_snmp/template_server_dell_idrac_snmp.yaml
# templates/server/hp_ilo_snmp/template_server_hp_ilo_snmp.yaml
# templates/server/ibm_imm_snmp/template_server_ibm_imm_snmp.yaml
# templates/server/supermicro_aten_snmp/template_server_supermicro_aten_snmp.yaml
# templates/tel/asterisk_http/template_tel_asterisk_http.yaml
# ui/include/classes/api/services/CValueMap.php
# ui/include/classes/validators/CApiInputValidator.php
# ui/include/defines.inc.php
# ui/tests/unit/include/classes/validators/CApiInputValidatorTest.php
Diffstat (limited to 'src')
-rw-r--r-- | src/go/plugins/proc/procfs_linux.go | 3 | ||||
-rw-r--r-- | src/libs/zbxcommon/str.c | 15 | ||||
-rw-r--r-- | src/libs/zbxdbcache/dbcache.c | 2 | ||||
-rw-r--r-- | src/libs/zbxdbcache/dbconfig.c | 14 | ||||
-rw-r--r-- | src/libs/zbxdbhigh/db.c | 3 | ||||
-rw-r--r-- | src/libs/zbxdbhigh/trigger.c | 4 | ||||
-rw-r--r-- | src/libs/zbxdbupgrade/dbupgrade_5030.c | 303 | ||||
-rw-r--r-- | src/libs/zbxeval/Makefile.am | 4 | ||||
-rw-r--r-- | src/libs/zbxeval/calc.c | 494 | ||||
-rw-r--r-- | src/libs/zbxeval/execute.c | 1408 | ||||
-rw-r--r-- | src/libs/zbxeval/misc.c | 4 | ||||
-rw-r--r-- | src/libs/zbxeval/parse.c | 2 | ||||
-rw-r--r-- | src/libs/zbxserver/evalfunc.c | 231 | ||||
-rw-r--r-- | src/libs/zbxserver/evalfunc2.c | 442 | ||||
-rw-r--r-- | src/libs/zbxserver/expression_eval.c | 9 | ||||
-rw-r--r-- | src/zabbix_server/dbsyncer/dbsyncer.c | 7 |
16 files changed, 2780 insertions, 165 deletions
diff --git a/src/go/plugins/proc/procfs_linux.go b/src/go/plugins/proc/procfs_linux.go index a4e01e9903f..cd9427647a4 100644 --- a/src/go/plugins/proc/procfs_linux.go +++ b/src/go/plugins/proc/procfs_linux.go @@ -139,9 +139,10 @@ func getProcesses(flags int) (processes []*procInfo, err error) { return nil, err } - if !entries[0].IsDir() { + if len(entries) < 1 || !entries[0].IsDir() { continue } + var pid int64 var tmperr error if pid, tmperr = strconv.ParseInt(entries[0].Name(), 10, 64); tmperr != nil { diff --git a/src/libs/zbxcommon/str.c b/src/libs/zbxcommon/str.c index 3cb5be162ce..d5e1a22aa96 100644 --- a/src/libs/zbxcommon/str.c +++ b/src/libs/zbxcommon/str.c @@ -2099,6 +2099,17 @@ size_t zbx_strlen_utf8(const char *text) return n; } +char *zbx_strshift_utf8(char *text, size_t num) +{ + while ('\0' != *text && 0 < num) + { + if (0x80 != (0xc0 & *(++text))) + num--; + } + + return text; +} + /****************************************************************************** * * * Function: zbx_utf8_char_len * @@ -4375,7 +4386,7 @@ int zbx_token_find(const char *expression, int pos, zbx_token_t *token, zbx_toke if (0 != (token_search & ZBX_TOKEN_SEARCH_REFERENCES)) { - while (NULL != (dollar = strchr(dollar, '$')) && (NULL == ptr || ptr > dollar)) + while (NULL != (dollar = strchr(dollar, '$')) && ptr > dollar) { if (0 == isdigit(dollar[1])) { @@ -4394,7 +4405,7 @@ int zbx_token_find(const char *expression, int pos, zbx_token_t *token, zbx_toke token_search &= ~ZBX_TOKEN_SEARCH_REFERENCES; } - if (NULL == ptr || '\0' == *ptr) + if ('\0' == *ptr) return FAIL; if ('\0' == ptr[1]) diff --git a/src/libs/zbxdbcache/dbcache.c b/src/libs/zbxdbcache/dbcache.c index 64fc243487c..34b84970069 100644 --- a/src/libs/zbxdbcache/dbcache.c +++ b/src/libs/zbxdbcache/dbcache.c @@ -63,7 +63,7 @@ static size_t sql_alloc = 4 * ZBX_KIBIBYTE; extern unsigned char program_type; extern int CONFIG_DOUBLE_PRECISION; -#define ZBX_IDS_SIZE 9 +#define ZBX_IDS_SIZE 10 #define ZBX_HC_ITEMS_INIT_SIZE 1000 diff --git a/src/libs/zbxdbcache/dbconfig.c b/src/libs/zbxdbcache/dbconfig.c index 020776a8b74..1fece7d4813 100644 --- a/src/libs/zbxdbcache/dbconfig.c +++ b/src/libs/zbxdbcache/dbconfig.c @@ -3690,6 +3690,7 @@ static void DCsync_triggers(zbx_dbsync_t *sync) ZBX_STR2UCHAR(trigger->state, row[7]); trigger->lastchange = atoi(row[8]); trigger->locked = 0; + trigger->timer_revision = 0; zbx_vector_ptr_create_ext(&trigger->tags, __config_mem_malloc_func, __config_mem_realloc_func, __config_mem_free_func); @@ -3726,10 +3727,14 @@ static void DCsync_triggers(zbx_dbsync_t *sync) /* force trigger list update for items used in removed trigger */ - zbx_get_serialized_expression_functionids(trigger->expression, trigger->expression_bin, - &functionids); + if (NULL != trigger->expression_bin) + { + zbx_get_serialized_expression_functionids(trigger->expression, trigger->expression_bin, + &functionids); + } - if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger->recovery_mode) + if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger->recovery_mode && + NULL != trigger->recovery_expression_bin) { zbx_get_serialized_expression_functionids(trigger->recovery_expression, trigger->recovery_expression_bin, &functionids); @@ -4192,6 +4197,9 @@ static void dc_schedule_trigger_timers(zbx_hashset_t *trend_queue, int now) if (ZBX_TRIGGER_TIMER_DEFAULT == trigger->timer) continue; + if (trigger->timer_revision == trigger->revision) + continue; + if (NULL == (timer = dc_trigger_timer_create(trigger))) continue; diff --git a/src/libs/zbxdbhigh/db.c b/src/libs/zbxdbhigh/db.c index 7b4bdc7ab36..849b8232c24 100644 --- a/src/libs/zbxdbhigh/db.c +++ b/src/libs/zbxdbhigh/db.c @@ -843,7 +843,8 @@ zbx_uint64_t DBget_maxid_num(const char *tablename, int num) 0 == strcmp(tablename, "alerts") || 0 == strcmp(tablename, "escalations") || 0 == strcmp(tablename, "autoreg_host") || - 0 == strcmp(tablename, "event_suppress")) + 0 == strcmp(tablename, "event_suppress") || + 0 == strcmp(tablename, "trigger_queue")) return DCget_nextid(tablename, num); return DBget_nextid(tablename, num); diff --git a/src/libs/zbxdbhigh/trigger.c b/src/libs/zbxdbhigh/trigger.c index 685c0ee3467..9f77daef0f8 100644 --- a/src/libs/zbxdbhigh/trigger.c +++ b/src/libs/zbxdbhigh/trigger.c @@ -688,7 +688,7 @@ void zbx_db_trigger_clean(DB_TRIGGER *trigger) * Purpose: get original trigger expression/recovery expression with expanded * * functions * * * - * Parameters: trigger - [IN] the trigger * + * Parameters: ctx - [IN] the parsed expression * * expression - [OUT] the trigger expression * * * ******************************************************************************/ @@ -801,7 +801,7 @@ void zbx_db_trigger_get_expression(const DB_TRIGGER *trigger, char **expression) * * * Function: zbx_db_trigger_get_recovery_expression * * * - * Purpose: get original trigger recovert expression with expanded functions * + * Purpose: get original trigger recovery expression with expanded functions * * * * Parameters: trigger - [IN] the trigger * * expression - [OUT] the trigger expression * diff --git a/src/libs/zbxdbupgrade/dbupgrade_5030.c b/src/libs/zbxdbupgrade/dbupgrade_5030.c index 47ceae7456a..d86adc8d289 100644 --- a/src/libs/zbxdbupgrade/dbupgrade_5030.c +++ b/src/libs/zbxdbupgrade/dbupgrade_5030.c @@ -3881,7 +3881,7 @@ static int DBpatch_5030123(void) return ret; } -static int DBpatch_5030124(void) +static int DBpatch_5030127(void) { #define CONDITION_TYPE_APPLICATION 15 if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER)) @@ -3897,7 +3897,7 @@ static int DBpatch_5030124(void) #undef CONDITION_TYPE_APPLICATION } -static int DBpatch_5030125(void) +static int DBpatch_5030128(void) { #define AUDIT_RESOURCE_APPLICATION 12 if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER)) @@ -3910,7 +3910,7 @@ static int DBpatch_5030125(void) #undef AUDIT_RESOURCE_APPLICATION } -static int DBpatch_5030126(void) +static int DBpatch_5030129(void) { if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER)) return SUCCEED; @@ -4099,7 +4099,7 @@ static int DBpatch_parse_applications_json(struct zbx_json_parse *jp, struct zbx return SUCCEED; } -static int DBpatch_5030127(void) +static int DBpatch_5030130(void) { DB_ROW row; DB_RESULT result; @@ -4160,7 +4160,7 @@ static int DBpatch_5030127(void) return ret; } -static int DBpatch_5030128(void) +static int DBpatch_5030131(void) { DB_ROW row; DB_RESULT result; @@ -4226,7 +4226,7 @@ out: return ret; } -static int DBpatch_5030129(void) +static int DBpatch_5030132(void) { if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER)) return SUCCEED; @@ -4238,57 +4238,57 @@ static int DBpatch_5030129(void) return SUCCEED; } -static int DBpatch_5030130(void) +static int DBpatch_5030133(void) { return DBdrop_foreign_key("httptest", 1); } -static int DBpatch_5030131(void) +static int DBpatch_5030134(void) { return DBdrop_index("httptest", "httptest_1"); } -static int DBpatch_5030132(void) +static int DBpatch_5030135(void) { return DBdrop_field("httptest", "applicationid"); } -static int DBpatch_5030133(void) +static int DBpatch_5030136(void) { return DBdrop_field("sysmaps_elements", "application"); } -static int DBpatch_5030134(void) +static int DBpatch_5030137(void) { return DBdrop_table("application_discovery"); } -static int DBpatch_5030135(void) +static int DBpatch_5030138(void) { return DBdrop_table("item_application_prototype"); } -static int DBpatch_5030136(void) +static int DBpatch_5030139(void) { return DBdrop_table("application_prototype"); } -static int DBpatch_5030137(void) +static int DBpatch_5030140(void) { return DBdrop_table("application_template"); } -static int DBpatch_5030138(void) +static int DBpatch_5030141(void) { return DBdrop_table("items_applications"); } -static int DBpatch_5030139(void) +static int DBpatch_5030142(void) { return DBdrop_table("applications"); } -static int DBpatch_5030140(void) +static int DBpatch_5030143(void) { DB_RESULT result; int ret; @@ -4308,7 +4308,7 @@ static int DBpatch_5030140(void) return ret; } -static int DBpatch_5030141(void) +static int DBpatch_5030144(void) { DB_RESULT result; int ret; @@ -4324,7 +4324,7 @@ static int DBpatch_5030141(void) return ret; } -static int DBpatch_5030142(void) +static int DBpatch_5030145(void) { const ZBX_TABLE table = {"report", "reportid", 0, @@ -4352,26 +4352,26 @@ static int DBpatch_5030142(void) return DBcreate_table(&table); } -static int DBpatch_5030143(void) +static int DBpatch_5030146(void) { return DBcreate_index("report", "report_1", "name", 1); } -static int DBpatch_5030144(void) +static int DBpatch_5030147(void) { const ZBX_FIELD field = {"userid", NULL, "users", "userid", 0, 0, 0, ZBX_FK_CASCADE_DELETE}; return DBadd_foreign_key("report", 1, &field); } -static int DBpatch_5030145(void) +static int DBpatch_5030148(void) { const ZBX_FIELD field = {"dashboardid", NULL, "dashboard", "dashboardid", 0, 0, 0, ZBX_FK_CASCADE_DELETE}; return DBadd_foreign_key("report", 2, &field); } -static int DBpatch_5030146(void) +static int DBpatch_5030149(void) { const ZBX_TABLE table = {"report_param", "reportparamid", 0, @@ -4388,19 +4388,19 @@ static int DBpatch_5030146(void) return DBcreate_table(&table); } -static int DBpatch_5030147(void) +static int DBpatch_5030150(void) { return DBcreate_index("report_param", "report_param_1", "reportid", 0); } -static int DBpatch_5030148(void) +static int DBpatch_5030151(void) { const ZBX_FIELD field = {"reportid", NULL, "report", "reportid", 0, 0, 0, ZBX_FK_CASCADE_DELETE}; return DBadd_foreign_key("report_param", 1, &field); } -static int DBpatch_5030149(void) +static int DBpatch_5030152(void) { const ZBX_TABLE table = {"report_user", "reportuserid", 0, @@ -4418,33 +4418,33 @@ static int DBpatch_5030149(void) return DBcreate_table(&table); } -static int DBpatch_5030150(void) +static int DBpatch_5030153(void) { return DBcreate_index("report_user", "report_user_1", "reportid", 0); } -static int DBpatch_5030151(void) +static int DBpatch_5030154(void) { const ZBX_FIELD field = {"reportid", NULL, "report", "reportid", 0, 0, 0, ZBX_FK_CASCADE_DELETE}; return DBadd_foreign_key("report_user", 1, &field); } -static int DBpatch_5030152(void) +static int DBpatch_5030155(void) { const ZBX_FIELD field = {"userid", NULL, "users", "userid", 0, 0, 0, ZBX_FK_CASCADE_DELETE}; return DBadd_foreign_key("report_user", 2, &field); } -static int DBpatch_5030153(void) +static int DBpatch_5030156(void) { const ZBX_FIELD field = {"access_userid", NULL, "users", "userid", 0, 0, 0, 0}; return DBadd_foreign_key("report_user", 3, &field); } -static int DBpatch_5030154(void) +static int DBpatch_5030157(void) { const ZBX_TABLE table = {"report_usrgrp", "reportusrgrpid", 0, @@ -4461,47 +4461,47 @@ static int DBpatch_5030154(void) return DBcreate_table(&table); } -static int DBpatch_5030155(void) +static int DBpatch_5030158(void) { return DBcreate_index("report_usrgrp", "report_usrgrp_1", "reportid", 0); } -static int DBpatch_5030156(void) +static int DBpatch_5030159(void) { const ZBX_FIELD field = {"reportid", NULL, "report", "reportid", 0, 0, 0, ZBX_FK_CASCADE_DELETE}; return DBadd_foreign_key("report_usrgrp", 1, &field); } -static int DBpatch_5030157(void) +static int DBpatch_5030160(void) { const ZBX_FIELD field = {"usrgrpid", NULL, "usrgrp", "usrgrpid", 0, 0, 0, ZBX_FK_CASCADE_DELETE}; return DBadd_foreign_key("report_usrgrp", 2, &field); } -static int DBpatch_5030158(void) +static int DBpatch_5030161(void) { const ZBX_FIELD field = {"access_userid", NULL, "users", "userid", 0, 0, 0, 0}; return DBadd_foreign_key("report_usrgrp", 3, &field); } -static int DBpatch_5030159(void) +static int DBpatch_5030162(void) { const ZBX_FIELD field = {"url", "", NULL, NULL, 255, ZBX_TYPE_CHAR, ZBX_NOTNULL, 0}; return DBadd_field("config", &field); } -static int DBpatch_5030160(void) +static int DBpatch_5030163(void) { const ZBX_FIELD field = {"report_test_timeout", "60s", NULL, NULL, 32, ZBX_TYPE_CHAR, ZBX_NOTNULL, 0}; return DBadd_field("config", &field); } -static int DBpatch_5030161(void) +static int DBpatch_5030164(void) { const ZBX_FIELD field = {"dbversion_status", "", NULL, NULL, 1024, ZBX_TYPE_CHAR, ZBX_NOTNULL, 0}; @@ -5486,7 +5486,7 @@ static int dbpatch_convert_trigger(zbx_dbpatch_trigger_t *trigger, zbx_vector_pt return SUCCEED; } -static int DBpatch_5030162(void) +static int DBpatch_5030165(void) { int i, ret = SUCCEED; DB_ROW row; @@ -5630,7 +5630,7 @@ static int DBpatch_5030162(void) return ret; } -static int DBpatch_5030163(void) +static int DBpatch_5030166(void) { if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER)) return SUCCEED; @@ -5820,7 +5820,7 @@ static int dbpatch_convert_expression_macro(const char *expression, const zbx_st return SUCCEED; } -static int DBpatch_5030164(void) +static int DBpatch_5030167(void) { DB_ROW row; DB_RESULT result; @@ -6014,7 +6014,7 @@ static char *dbpatch_formula_to_expression(zbx_uint64_t itemid, const char *form return exp; } -static int DBpatch_5030165(void) +static int DBpatch_5030168(void) { DB_ROW row; DB_RESULT result; @@ -6224,7 +6224,7 @@ static int dbpatch_aggregate2formula(const char *itemid, const AGENT_REQUEST *re return SUCCEED; } -static int DBpatch_5030166(void) +static int DBpatch_5030169(void) { DB_ROW row; DB_RESULT result; @@ -6246,7 +6246,12 @@ static int DBpatch_5030166(void) params_offset = 0; init_request(&request); - parse_item_key(row[1], &request); + + if (SUCCEED != parse_item_key(row[1], &request)) + { + zabbix_log(LOG_LEVEL_WARNING, "Cannot parse aggregate checks item key \"%s\"", row[1]); + continue; + } ret_formula = dbpatch_aggregate2formula(row[0], &request, ¶ms, ¶ms_alloc, ¶ms_offset, &error); @@ -6283,7 +6288,7 @@ static int DBpatch_5030166(void) return ret; } -static int DBpatch_5030167(void) +static int DBpatch_5030170(void) { #ifdef HAVE_MYSQL return DBcreate_index("items", "items_8", "key_(1024)", 0); @@ -6292,6 +6297,157 @@ static int DBpatch_5030167(void) #endif } +static int DBpatch_5030171(void) +{ + return DBrename_table("trigger_queue", "trigger_queue_tmp"); +} + +static int DBpatch_5030172(void) +{ + const ZBX_TABLE table = + {"trigger_queue", "trigger_queueid", 0, + { + {"trigger_queueid", NULL, NULL, NULL, 0, ZBX_TYPE_ID, ZBX_NOTNULL, 0}, + {"objectid", NULL, NULL, NULL, 0, ZBX_TYPE_ID, ZBX_NOTNULL, 0}, + {"type", "0", NULL, NULL, 0, ZBX_TYPE_INT, ZBX_NOTNULL, 0}, + {"clock", "0", NULL, NULL, 0, ZBX_TYPE_INT, ZBX_NOTNULL, 0}, + {"ns", "0", NULL, NULL, 0, ZBX_TYPE_INT, ZBX_NOTNULL, 0}, + {0} + }, + NULL + }; + + return DBcreate_table(&table); +} + +static int DBpatch_5030173(void) +{ + DB_RESULT result; + DB_ROW row; + zbx_db_insert_t db_insert; + zbx_uint64_t objectid, type, clock, ns; + int ret; + + zbx_db_insert_prepare(&db_insert, "trigger_queue", "trigger_queueid", "objectid", "type", "clock", "ns", NULL); + + result = DBselect("select objectid,type,clock,ns from trigger_queue_tmp"); + + while (NULL != (row = DBfetch(result))) + { + ZBX_STR2UINT64(objectid, row[0]); + ZBX_STR2UINT64(type, row[1]); + ZBX_STR2UINT64(clock, row[2]); + ZBX_STR2UINT64(ns, row[3]); + + zbx_db_insert_add_values(&db_insert, __UINT64_C(0), objectid, type, clock, ns); + } + DBfree_result(result); + + zbx_db_insert_autoincrement(&db_insert, "trigger_queueid"); + ret = zbx_db_insert_execute(&db_insert); + zbx_db_insert_clean(&db_insert); + + return ret; +} + +static int DBpatch_5030174(void) +{ + return DBdrop_table("trigger_queue_tmp"); +} + +static int DBpatch_5030175(void) +{ + const ZBX_FIELD field = {"type", "0", NULL, NULL, 0, ZBX_TYPE_INT, ZBX_NOTNULL, 0}; + + return DBadd_field("valuemap_mapping", &field); +} + +static int DBpatch_5030176(void) +{ + return DBdrop_foreign_key("valuemap_mapping", 1); +} + +static int DBpatch_5030177(void) +{ + return DBdrop_index("valuemap_mapping", "valuemap_mapping_1"); +} + +static int DBpatch_5030178(void) +{ + return DBcreate_index("valuemap_mapping", "valuemap_mapping_1", "valuemapid,value,type", 1); +} + +static int DBpatch_5030179(void) +{ + const ZBX_FIELD field = {"valuemapid", NULL, "valuemap", "valuemapid", 0, 0, 0, ZBX_FK_CASCADE_DELETE}; + + return DBadd_foreign_key("valuemap_mapping", 1, &field); +} + +static int DBpatch_5030180(void) +{ + const ZBX_FIELD field = {"sortorder", "0", NULL, NULL, 0, ZBX_TYPE_INT, ZBX_NOTNULL, 0}; + + return DBadd_field("valuemap_mapping", &field); +} + +static int DBpatch_5030181(void) +{ + int ret = SUCCEED; + DB_ROW row; + DB_RESULT result; + + if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER)) + return ret; + + result = DBselect("select valuemapid from valuemap order by valuemapid asc"); + + while (NULL != (row = DBfetch(result))) + { + int i = 0; + char *sql = NULL; + zbx_uint64_t valuemapid; + size_t sql_alloc = 0, sql_offset = 0; + DB_ROW in_row; + DB_RESULT in_result; + + ZBX_DBROW2UINT64(valuemapid, row[0]); + + DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + in_result = DBselect("select valuemap_mappingid" + " from valuemap_mapping" + " where valuemapid=" ZBX_FS_UI64 + " order by valuemap_mappingid asc", valuemapid); + + while (NULL != (in_row = DBfetch(in_result))) + { + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, + "update valuemap_mapping set sortorder=%d where valuemap_mappingid=%s;\n", + i, in_row[0]); + i++; + + if (SUCCEED != (ret = DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset))) + goto out; + } + + DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + if (16 < sql_offset && ZBX_DB_OK > DBexecute("%s", sql)) + ret = FAIL; +out: + DBfree_result(in_result); + zbx_free(sql); + + if (FAIL == ret) + break; + } + + DBfree_result(result); + + return ret; +} + #undef HOST_STATUS_TEMPLATE #define HOST_STATUS_TEMPLATE 3 #undef ZBX_FLAG_DISCOVERY_NORMAL @@ -6303,56 +6459,56 @@ static int DBpatch_5030167(void) #define ZBX_FIELD_UUID {"uuid", "", NULL, NULL, 32, ZBX_TYPE_CHAR, ZBX_NOTNULL, 0} -static int DBpatch_5030168(void) +static int DBpatch_5030182(void) { const ZBX_FIELD field = ZBX_FIELD_UUID; return DBadd_field("items", &field); } -static int DBpatch_5030169(void) +static int DBpatch_5030183(void) { const ZBX_FIELD field = ZBX_FIELD_UUID; return DBadd_field("hosts", &field); } -static int DBpatch_5030170(void) +static int DBpatch_5030184(void) { const ZBX_FIELD field = ZBX_FIELD_UUID; return DBadd_field("triggers", &field); } -static int DBpatch_5030171(void) +static int DBpatch_5030185(void) { const ZBX_FIELD field = ZBX_FIELD_UUID; return DBadd_field("dashboard", &field); } -static int DBpatch_5030172(void) +static int DBpatch_5030186(void) { const ZBX_FIELD field = ZBX_FIELD_UUID; return DBadd_field("graphs", &field); } -static int DBpatch_5030173(void) +static int DBpatch_5030187(void) { const ZBX_FIELD field = ZBX_FIELD_UUID; return DBadd_field("hstgrp", &field); } -static int DBpatch_5030174(void) +static int DBpatch_5030188(void) { const ZBX_FIELD field = ZBX_FIELD_UUID; return DBadd_field("httptest", &field); } -static int DBpatch_5030175(void) +static int DBpatch_5030189(void) { const ZBX_FIELD field = ZBX_FIELD_UUID; @@ -6415,7 +6571,7 @@ static char *DBpatch_make_trigger_function(const char *name, const char *tpl, co return func; } -static int DBpatch_5030176(void) +static int DBpatch_5030190(void) { int ret = SUCCEED; char *name, *uuid, *sql = NULL; @@ -6459,7 +6615,7 @@ out: return ret; } -static int DBpatch_5030177(void) +static int DBpatch_5030191(void) { int ret = SUCCEED; char *name, *uuid, *sql = NULL, *seed = NULL; @@ -6506,7 +6662,7 @@ out: return ret; } -static int DBpatch_5030178(void) +static int DBpatch_5030192(void) { int ret = SUCCEED; char *uuid, *sql = NULL, *seed = NULL; @@ -6636,7 +6792,7 @@ out: return ret; } -static int DBpatch_5030179(void) +static int DBpatch_5030193(void) { int ret = SUCCEED; char *host_name, *uuid, *sql = NULL, *seed = NULL; @@ -6705,7 +6861,7 @@ out: return ret; } -static int DBpatch_5030180(void) +static int DBpatch_5030194(void) { int ret = SUCCEED; char *template_name, *uuid, *sql = NULL, *seed = NULL; @@ -6752,7 +6908,7 @@ out: return ret; } -static int DBpatch_5030181(void) +static int DBpatch_5030195(void) { int ret = SUCCEED; char *template_name, *uuid, *sql = NULL, *seed = NULL; @@ -6799,7 +6955,7 @@ out: return ret; } -static int DBpatch_5030182(void) +static int DBpatch_5030196(void) { int ret = SUCCEED; char *template_name, *uuid, *sql = NULL, *seed = NULL; @@ -6846,7 +7002,7 @@ out: return ret; } -static int DBpatch_5030183(void) +static int DBpatch_5030197(void) { int ret = SUCCEED; char *uuid, *sql = NULL; @@ -6883,7 +7039,7 @@ out: return ret; } -static int DBpatch_5030184(void) +static int DBpatch_5030198(void) { int ret = SUCCEED; char *template_name, *uuid, *sql = NULL, *seed = NULL; @@ -6932,7 +7088,7 @@ out: return ret; } -static int DBpatch_5030185(void) +static int DBpatch_5030199(void) { int ret = SUCCEED; char *uuid, *sql = NULL, *seed = NULL; @@ -7081,7 +7237,7 @@ out: return ret; } -static int DBpatch_5030186(void) +static int DBpatch_5030200(void) { int ret = SUCCEED; char *templ_name, *uuid, *sql = NULL, *seed = NULL; @@ -7132,7 +7288,7 @@ out: return ret; } -static int DBpatch_5030187(void) +static int DBpatch_5030201(void) { int ret = SUCCEED; char *name_tmpl, *uuid, *seed = NULL, *sql = NULL; @@ -7316,9 +7472,6 @@ DBPATCH_ADD(5030120, 0, 1) DBPATCH_ADD(5030121, 0, 1) DBPATCH_ADD(5030122, 0, 1) DBPATCH_ADD(5030123, 0, 1) -DBPATCH_ADD(5030124, 0, 1) -DBPATCH_ADD(5030125, 0, 1) -DBPATCH_ADD(5030126, 0, 1) DBPATCH_ADD(5030127, 0, 1) DBPATCH_ADD(5030128, 0, 1) DBPATCH_ADD(5030129, 0, 1) @@ -7380,5 +7533,19 @@ DBPATCH_ADD(5030184, 0, 1) DBPATCH_ADD(5030185, 0, 1) DBPATCH_ADD(5030186, 0, 1) DBPATCH_ADD(5030187, 0, 1) +DBPATCH_ADD(5030188, 0, 1) +DBPATCH_ADD(5030189, 0, 1) +DBPATCH_ADD(5030190, 0, 1) +DBPATCH_ADD(5030191, 0, 1) +DBPATCH_ADD(5030192, 0, 1) +DBPATCH_ADD(5030193, 0, 1) +DBPATCH_ADD(5030194, 0, 1) +DBPATCH_ADD(5030195, 0, 1) +DBPATCH_ADD(5030196, 0, 1) +DBPATCH_ADD(5030197, 0, 1) +DBPATCH_ADD(5030198, 0, 1) +DBPATCH_ADD(5030199, 0, 1) +DBPATCH_ADD(5030200, 0, 1) +DBPATCH_ADD(5030201, 0, 1) DBPATCH_END() diff --git a/src/libs/zbxeval/Makefile.am b/src/libs/zbxeval/Makefile.am index c6d4dc4c93a..66e43e226b4 100644 --- a/src/libs/zbxeval/Makefile.am +++ b/src/libs/zbxeval/Makefile.am @@ -6,4 +6,6 @@ libzbxeval_a_SOURCES = \ parse.c \ execute.c \ misc.c \ - query.c + query.c \ + calc.c \ + eval.h diff --git a/src/libs/zbxeval/calc.c b/src/libs/zbxeval/calc.c new file mode 100644 index 00000000000..e3a9b52370e --- /dev/null +++ b/src/libs/zbxeval/calc.c @@ -0,0 +1,494 @@ +/* +** Zabbix +** Copyright (C) 2001-2020 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 "common.h" +#include "zbxalgo.h" +#include "zbxeval.h" + +static int zbx_is_normal_double(double dbl) +{ + if (FP_ZERO != fpclassify(dbl) && FP_NORMAL != fpclassify(dbl)) + return FAIL; + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: calc_arithmetic_mean * + * * + * Purpose: calculate arithmetic mean (i.e. average) * + * * + * Parameters: v - [IN] non-empty vector with input data * + * * + * Return value: arithmetic mean value * + * * + ******************************************************************************/ +static double calc_arithmetic_mean(const zbx_vector_dbl_t *v) +{ + double sum = 0; + int i; + + for (i = 0; i < v->values_num; i++) + sum += v->values[i]; + + return sum / v->values_num; +} + +/****************************************************************************** + * * + * Function: zbx_eval_calc_kurtosis * + * * + * Purpose: evaluate function 'kurtosis' * + * * + * Parameters: values - [IN] non-empty vector with input data * + * result - [OUT] calculated value * + * error - [OUT] dynamically allocated error message * + * * + * Return value: SUCCEED - evaluated successfully * + * FAIL - failed to evaluate function (see 'error') * + * * + ******************************************************************************/ +int zbx_eval_calc_kurtosis(zbx_vector_dbl_t *values, double *result, char **error) +{ + double mean, second_moment = 0, fourth_moment = 0, second_moment2, res; + int i; + + /* step 1: calculate arithmetic mean */ + mean = calc_arithmetic_mean(values); + + if (SUCCEED != zbx_is_normal_double(mean)) + goto err; + + /* step 2: calculate the second and the fourth moments */ + + for (i = 0; i < values->values_num; i++) + { + double diff = values->values[i] - mean; + + second_moment += diff * diff; + fourth_moment += diff * diff * diff * diff; + } + + second_moment /= values->values_num; + fourth_moment /= values->values_num; + + /* step 3: calculate kurtosis */ + + second_moment2 = second_moment * second_moment; + + if (FP_NORMAL != fpclassify(second_moment2) || SUCCEED != zbx_is_normal_double(fourth_moment)) + goto err; + + res = fourth_moment / second_moment2; + + if (SUCCEED != zbx_is_normal_double(res)) + goto err; + + *result = res; + + return SUCCEED; +err: + *error = zbx_strdup(*error, "cannot calculate kurtosis() value"); + + return FAIL; +} + +static int zbx_vector_dbl_compare(const void *d1, const void *d2) +{ + const double *p1 = (const double *)d1; + const double *p2 = (const double *)d2; + + ZBX_RETURN_IF_NOT_EQUAL(*p1, *p2); + + return 0; +} + +/****************************************************************************** + * * + * Function: find_median * + * * + * Purpose: find median (helper function) * + * * + * Parameters: v - [IN/OUT] non-empty vector with input data. * + * NOTE: it will be modified (sorted in place). * + * * + * Return value: median * + * * + ******************************************************************************/ +static double find_median(zbx_vector_dbl_t *v) +{ + zbx_vector_dbl_sort(v, zbx_vector_dbl_compare); + + if (0 == v->values_num % 2) /* number of elements is even */ + return (v->values[v->values_num / 2 - 1] + v->values[v->values_num / 2]) / 2.0; + else + return v->values[v->values_num / 2]; +} + +/****************************************************************************** + * * + * Function: zbx_eval_calc_mad * + * * + * Purpose: calculate 'median absolute deviation' * + * * + * Parameters: values - [IN] non-empty vector with input data. * + * NOTE: its elements will be modified and should * + * not be used in the caller! * + * result - [OUT] calculated value * + * error - [OUT] dynamically allocated error message * + * * + * Return value: SUCCEED - evaluated successfully * + * FAIL - failed to evaluate function (see 'error') * + * * + ******************************************************************************/ +int zbx_eval_calc_mad(zbx_vector_dbl_t *values, double *result, char **error) +{ + double median; + int i; + + /* step 1: find median of input data */ + median = find_median(values); + + if (SUCCEED != zbx_is_normal_double(median)) + goto err; + + /* step 2: find absolute differences of input data and median. Reuse input data vector. */ + + for (i = 0; i < values->values_num; i++) + values->values[i] = fabs(values->values[i] - median); + + /* step 3: find median of the differences */ + median = find_median(values); + + if (SUCCEED != zbx_is_normal_double(median)) + goto err; + + *result = median; + + return SUCCEED; +err: + *error = zbx_strdup(*error, "cannot calculate mad() value"); + + return FAIL; +} + +/****************************************************************************** + * * + * Function: zbx_eval_calc_skewness * + * * + * Purpose: evaluate 'skewness' function * + * * + * Parameters: values - [IN] non-empty vector with input data * + * result - [OUT] calculated value * + * error - [OUT] dynamically allocated error message * + * * + * Return value: SUCCEED - evaluated successfully * + * FAIL - failed to evaluate function (see 'error') * + * * + ******************************************************************************/ +int zbx_eval_calc_skewness(zbx_vector_dbl_t *values, double *result, char **error) +{ + double mean, std_dev = 0, sum_diff3 = 0, divisor; + int i; + + /* step 1: calculate arithmetic mean */ + mean = calc_arithmetic_mean(values); + + if (SUCCEED != zbx_is_normal_double(mean)) + goto err; + + /* step 2: calculate the standard deviation and sum_diff3 */ + + for (i = 0; i < values->values_num; i++) + { + double diff = values->values[i] - mean; + + std_dev += diff * diff; + sum_diff3 += diff * diff * diff; + } + + std_dev = sqrt(std_dev / values->values_num); + + /* step 3: calculate skewness */ + + divisor = values->values_num * std_dev * std_dev * std_dev; + + if (FP_NORMAL != fpclassify(divisor) || SUCCEED != zbx_is_normal_double(sum_diff3)) + goto err; + + *result = sum_diff3 / divisor; + + return SUCCEED; +err: + *error = zbx_strdup(*error, "cannot calculate skewness() value"); + + return FAIL; +} + +/****************************************************************************** + * * + * Function: zbx_eval_calc_stddevpop * + * * + * Purpose: evaluate function 'stdevpop' (population standard deviation) * + * * + * Parameters: values - [IN] non-empty vector with input data * + * result - [OUT] calculated value * + * error - [OUT] dynamically allocated error message * + * * + * Return value: SUCCEED - evaluated successfully * + * FAIL - failed to evaluate function (see 'error') * + * * + * Comments: the algorithm was taken from "Population standard deviation of * + * grades of eight students" in * + * https://en.wikipedia.org/wiki/Standard_deviation * + * * + ******************************************************************************/ +int zbx_eval_calc_stddevpop(zbx_vector_dbl_t *values, double *result, char **error) +{ + double mean, std_dev = 0; + int i; + + /* step 1: calculate arithmetic mean */ + mean = calc_arithmetic_mean(values); + + if (SUCCEED != zbx_is_normal_double(mean)) + goto err; + + /* step 2: calculate the standard deviation */ + + for (i = 0; i < values->values_num; i++) + { + double diff = values->values[i] - mean; + + std_dev += diff * diff; + } + + std_dev = sqrt(std_dev / values->values_num); + + if (SUCCEED != zbx_is_normal_double(std_dev)) + goto err; + + *result = std_dev; + + return SUCCEED; +err: + *error = zbx_strdup(*error, "cannot calculate stddevpop() value"); + + return FAIL; +} + +/****************************************************************************** + * * + * Function: zbx_eval_calc_stddevsamp * + * * + * Purpose: evaluate function 'stddevsamp' (sample standard deviation) * + * * + * Parameters: values - [IN] vector with input data with at least 2 elements * + * result - [OUT] calculated value * + * error - [OUT] dynamically allocated error message * + * * + * Return value: SUCCEED - evaluated successfully * + * FAIL - failed to evaluate function (see 'error') * + * * + * Comments: the algorithm was taken from "Population standard deviation of * + * grades of eight students" in * + * https://en.wikipedia.org/wiki/Standard_deviation * + * * + ******************************************************************************/ +int zbx_eval_calc_stddevsamp(zbx_vector_dbl_t *values, double *result, char **error) +{ + double mean, std_dev = 0; + int i; + + if (2 > values->values_num) /* stddevsamp requires at least 2 data values */ + { + *error = zbx_strdup(*error, "not enough data"); + return FAIL; + } + + /* step 1: calculate arithmetic mean */ + mean = calc_arithmetic_mean(values); + + if (SUCCEED != zbx_is_normal_double(mean)) + goto err; + + /* step 2: calculate the standard deviation */ + + for (i = 0; i < values->values_num; i++) + { + double diff = values->values[i] - mean; + + std_dev += diff * diff; + } + + std_dev = sqrt(std_dev / (values->values_num - 1)); /* divided by 'n - 1' because */ + /* sample standard deviation */ + if (SUCCEED != zbx_is_normal_double(std_dev)) + goto err; + + *result = std_dev; + + return SUCCEED; +err: + *error = zbx_strdup(*error, "cannot calculate stddevsamp() value"); + + return FAIL; +} + +/****************************************************************************** + * * + * Function: zbx_eval_calc_sumofsquares * + * * + * Purpose: calculate sum of squares * + * * + * Parameters: values - [IN] non-empty vector with input data * + * result - [OUT] calculated value * + * error - [OUT] dynamically allocated error message * + * * + * Return value: SUCCEED - evaluated successfully * + * FAIL - failed to evaluate function (see 'error') * + * * + ******************************************************************************/ +int zbx_eval_calc_sumofsquares(zbx_vector_dbl_t *values, double *result, char **error) +{ + double sum = 0; + int i; + + for (i = 0; i < values->values_num; i++) + sum += values->values[i] * values->values[i]; + + if (SUCCEED != zbx_is_normal_double(sum)) + { + *error = zbx_strdup(*error, "cannot calculate sumofsquares() value"); + return FAIL; + } + + *result = sum; + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: zbx_eval_calc_varpop * + * * + * Purpose: evaluate function 'varpop' (population variance) * + * * + * Parameters: values - [IN] non-empty vector with input data * + * result - [OUT] calculated value * + * error - [OUT] dynamically allocated error message * + * * + * Return value: SUCCEED - evaluated successfully * + * FAIL - failed to evaluate function (see 'error') * + * * + * Comments: the algorithm was taken from "Population variance" in * + * https://en.wikipedia.org/wiki/Variance#Population_variance * + * * + ******************************************************************************/ +int zbx_eval_calc_varpop(zbx_vector_dbl_t *values, double *result, char **error) +{ + double mean, res = 0; + int i; + + /* step 1: calculate arithmetic mean */ + mean = calc_arithmetic_mean(values); + + if (SUCCEED != zbx_is_normal_double(mean)) + goto err; + + /* step 2: calculate the population variance */ + + for (i = 0; i < values->values_num; i++) + { + double diff = values->values[i] - mean; + + res += diff * diff; + } + + res /= values->values_num; /* divide by 'number of values' for population variance */ + + if (SUCCEED != zbx_is_normal_double(res)) + goto err; + + *result = res; + + return SUCCEED; +err: + *error = zbx_strdup(*error, "cannot calculate varpop() value"); + + return FAIL; +} + +/****************************************************************************** + * * + * Function: zbx_eval_calc_varsamp * + * * + * Purpose: evaluate function 'varsamp' (sample variance) * + * * + * Parameters: values - [IN] non-empty vector with input data * + * result - [OUT] calculated value * + * error - [OUT] dynamically allocated error message * + * * + * Return value: SUCCEED - evaluated successfully * + * FAIL - failed to evaluate function (see 'error') * + * * + * Comments: the algorithm was taken from "Sample variance" in * + * https://en.wikipedia.org/wiki/Variance#Population_variance * + * * + ******************************************************************************/ +int zbx_eval_calc_varsamp(zbx_vector_dbl_t *values, double *result, char **error) +{ + double mean, res = 0; + int i; + + if (2 > values->values_num) /* varsamp requires at least 2 data values */ + { + *error = zbx_strdup(*error, "not enough data"); + return FAIL; + } + + /* step 1: calculate arithmetic mean */ + mean = calc_arithmetic_mean(values); + + if (SUCCEED != zbx_is_normal_double(mean)) + goto err; + + /* step 2: calculate the sample variance */ + + for (i = 0; i < values->values_num; i++) + { + double diff = values->values[i] - mean; + + res += diff * diff; + } + + res /= values->values_num - 1; /* divide by 'number of values' - 1 for unbiased sample variance */ + + if (SUCCEED != zbx_is_normal_double(res)) + goto err; + + *result = res; + + return SUCCEED; +err: + *error = zbx_strdup(*error, "cannot calculate varsamp() value"); + + return FAIL; +} diff --git a/src/libs/zbxeval/execute.c b/src/libs/zbxeval/execute.c index f8f16a6f806..603ed06c279 100644 --- a/src/libs/zbxeval/execute.c +++ b/src/libs/zbxeval/execute.c @@ -26,6 +26,26 @@ /* exit code in addition to SUCCEED/FAIL */ #define UNKNOWN 1 +/* bit function types */ +typedef enum +{ + FUNCTION_OPTYPE_BIT_AND = 0, + FUNCTION_OPTYPE_BIT_OR, + FUNCTION_OPTYPE_BIT_XOR, + FUNCTION_OPTYPE_BIT_LSHIFT, + FUNCTION_OPTYPE_BIT_RSHIFT +} +zbx_function_bit_optype_t; + +/* trim function types */ +typedef enum +{ + FUNCTION_OPTYPE_TRIM_ALL = 0, + FUNCTION_OPTYPE_TRIM_LEFT, + FUNCTION_OPTYPE_TRIM_RIGHT +} +zbx_function_trim_optype_t; + /****************************************************************************** * * * Function: variant_convert_suffixed_num * @@ -110,6 +130,13 @@ static int eval_execute_op_unary(const zbx_eval_context_t *ctx, const zbx_eval_t return FAIL; } + if (FP_ZERO != fpclassify(value) && FP_NORMAL != fpclassify(value)) + { + *error = zbx_dsprintf(*error, "calculation resulted in NaN or Infinity at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + zbx_variant_clear(right); zbx_variant_set_dbl(right, value); @@ -353,6 +380,14 @@ static int eval_execute_op_binary(const zbx_eval_context_t *ctx, const zbx_eval_ value = left->data.dbl / right->data.dbl; break; } + + if (FP_ZERO != fpclassify(value) && FP_NORMAL != fpclassify(value)) + { + *error = zbx_dsprintf(*error, "calculation resulted in NaN or Infinity at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + finish: zbx_variant_clear(left); zbx_variant_clear(right); @@ -539,13 +574,14 @@ int eval_compare_token(const zbx_eval_context_t *ctx, const zbx_strloc_t *loc, c * return value. * * * ******************************************************************************/ -static void eval_function_return(int args_num, zbx_variant_t *value, zbx_vector_var_t *output) +static void eval_function_return(zbx_uint32_t args_num, zbx_variant_t *value, zbx_vector_var_t *output) { int i; - for (i = output->values_num - args_num; i < output->values_num; i++) + for (i = output->values_num - (int)args_num; i < output->values_num; i++) zbx_variant_clear(&output->values[i]); - output->values_num -= args_num; + + output->values_num -= (int)args_num; zbx_vector_var_append_ptr(output, value); } @@ -1209,12 +1245,14 @@ static int eval_execute_function_dayofmonth(const zbx_eval_context_t *ctx, const /****************************************************************************** * * - * Function: eval_execute_function_bitand * + * Function: eval_execute_function_bitwise * * * - * Purpose: evaluate bitand() function * + * Purpose: evaluate bitand(), bitor(), bitxor(), bitlshift(), * + * bitrshift() functions * * * * Parameters: ctx - [IN] the evaluation context * * token - [IN] the function token * + * type - [IN] the function type * * output - [IN/OUT] the output value stack * * error - [OUT] the error message in the case of failure * * * @@ -1222,8 +1260,8 @@ static int eval_execute_function_dayofmonth(const zbx_eval_context_t *ctx, const * FAIL - otherwise * * * ******************************************************************************/ -static int eval_execute_function_bitand(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, - zbx_vector_var_t *output, char **error) +static int eval_execute_function_bitwise(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_function_bit_optype_t type, zbx_vector_var_t *output, char **error) { zbx_variant_t value, *left, *right; int ret; @@ -1241,21 +1279,652 @@ static int eval_execute_function_bitand(const zbx_eval_context_t *ctx, const zbx left = &output->values[output->values_num - 2]; right = &output->values[output->values_num - 1]; - if (SUCCEED != zbx_variant_convert(left, ZBX_VARIANT_UI64)) + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, left, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, right, error)) { - *error = zbx_dsprintf(*error, "function argument \"%s\" is not an unsigned integer value at \"%s\"", - zbx_variant_value_desc(left), ctx->expression + token->loc.l); return FAIL; } - if (SUCCEED != zbx_variant_convert(right, ZBX_VARIANT_UI64)) + switch (type) { - *error = zbx_dsprintf(*error, "function argument \"%s\" is not an unsigned integer value at \"%s\"", - zbx_variant_value_desc(right), ctx->expression + token->loc.l); + case FUNCTION_OPTYPE_BIT_AND: + zbx_variant_set_ui64(&value, left->data.ui64 & right->data.ui64); + break; + case FUNCTION_OPTYPE_BIT_OR: + zbx_variant_set_ui64(&value, left->data.ui64 | right->data.ui64); + break; + case FUNCTION_OPTYPE_BIT_XOR: + zbx_variant_set_ui64(&value, left->data.ui64 ^ right->data.ui64); + break; + case FUNCTION_OPTYPE_BIT_LSHIFT: + zbx_variant_set_ui64(&value, left->data.ui64 << right->data.ui64); + break; + case FUNCTION_OPTYPE_BIT_RSHIFT: + zbx_variant_set_ui64(&value, left->data.ui64 >> right->data.ui64); + } + + eval_function_return(2, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_bitnot * + * * + * Purpose: evaluate bitnot() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_bitnot(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + zbx_variant_t value, *arg; + int ret; + + if (1 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + arg = &output->values[output->values_num - 1]; + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, arg, error)) + return FAIL; + + zbx_variant_set_ui64(&value, ~arg->data.ui64); + eval_function_return(1, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_left * + * * + * Purpose: evaluate left() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_left(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *arg, *len, value; + size_t sz; + char *strval; + + if (2 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + arg = &output->values[output->values_num - 2]; + len = &output->values[output->values_num - 1]; + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, len, error)) + { + return FAIL; + } + + sz = zbx_strlen_utf8_nchars(arg->data.str, (size_t)len->data.ui64) + 1; + strval = zbx_malloc(NULL, sz); + zbx_strlcpy_utf8(strval, arg->data.str, sz); + + zbx_variant_set_str(&value, strval); + eval_function_return(2, &value, output); + + return SUCCEED; +} + +static int eval_validate_statistical_function_args(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int i, ret; + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + if (1 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + i = output->values_num - 1; + + if (ZBX_VARIANT_DBL_VECTOR != output->values[i].type) + { + *error = zbx_dsprintf(*error, "invalid argument type \"%s\" for function at \"%s\"", + zbx_variant_type_desc(&output->values[i]), ctx->expression + token->loc.l); + return FAIL; + } + + if (0 == output->values[i].data.dbl_vector->values_num) + { + *error = zbx_dsprintf(*error, "empty vector argument for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + return UNKNOWN; +} + +/****************************************************************************** + * * + * Function: eval_execute_statistical_function * + * * + * Purpose: common operations for aggregate function calculation * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * stat_func - [IN] pointer to aggregate function to be called * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_statistical_function(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_statistical_func_t stat_func, zbx_vector_var_t *output, char **error) +{ + int ret; + double result; + zbx_variant_t value; + zbx_vector_dbl_t *dbl_vector; + + if (UNKNOWN != (ret = eval_validate_statistical_function_args(ctx, token, output, error))) + return ret; + + dbl_vector = output->values[output->values_num - (int)token->opt].data.dbl_vector; + + if (FAIL == stat_func(dbl_vector, &result, error)) + return FAIL; + + zbx_variant_set_dbl(&value, result); + eval_function_return((int)token->opt, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_right * + * * + * Purpose: evaluate right() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_right(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *arg, *len, value; + size_t sz, srclen; + char *strval, *p; + + if (2 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + arg = &output->values[output->values_num - 2]; + len = &output->values[output->values_num - 1]; + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, len, error)) + { + return FAIL; + } + + srclen = zbx_strlen_utf8(arg->data.str); + + if (len->data.ui64 < srclen) + { + p = zbx_strshift_utf8(arg->data.str, srclen - len->data.ui64); + sz = zbx_strlen_utf8_nchars(p, (size_t)len->data.ui64) + 1; + strval = zbx_malloc(NULL, sz); + zbx_strlcpy_utf8(strval, p, sz); + } + else + strval = zbx_strdup(NULL, arg->data.str); + + zbx_variant_set_str(&value, strval); + eval_function_return(2, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_mid * + * * + * Purpose: evaluate mid() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_mid(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *arg, *start, *len, value; + size_t sz, srclen; + char *strval, *p; + + if (3 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + arg = &output->values[output->values_num - 3]; + start = &output->values[output->values_num - 2]; + len = &output->values[output->values_num - 1]; + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, start, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, len, error)) + { + return FAIL; + } + + srclen = zbx_strlen_utf8(arg->data.str); + + if (0 == start->data.ui64 || start->data.ui64 > srclen) + { + *error = zbx_dsprintf(*error, "invalid function second argument at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + p = zbx_strshift_utf8(arg->data.str, start->data.ui64 - 1); + + if (srclen > start->data.ui64 + len->data.ui64) + { + sz = zbx_strlen_utf8_nchars(p, len->data.ui64) + 1; + strval = zbx_malloc(NULL, sz); + zbx_strlcpy_utf8(strval, p, sz); + } + else + strval = zbx_strdup(NULL, p); + + zbx_variant_set_str(&value, strval); + eval_function_return(3, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_trim * + * * + * Purpose: evaluate trim(), rtrim(), ltrim() functions * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * type - [IN] the function type * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_trim(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_function_trim_optype_t type, zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *sym, *arg, value, sym_val; + + if (1 > token->opt || 2 < token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + if (2 == token->opt) + { + arg = &output->values[output->values_num - 2]; + sym = &output->values[output->values_num - 1]; + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, sym, error)) + return FAIL; + } + else + { + arg = &output->values[output->values_num - 1]; + zbx_variant_set_str(&sym_val, zbx_strdup(NULL, ZBX_WHITESPACE)); + sym = &sym_val; + } + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error)) + return FAIL; + + switch (type) + { + case FUNCTION_OPTYPE_TRIM_ALL: + zbx_lrtrim(arg->data.str, sym->data.str); + break; + case FUNCTION_OPTYPE_TRIM_RIGHT: + zbx_rtrim(arg->data.str, sym->data.str); + break; + case FUNCTION_OPTYPE_TRIM_LEFT: + zbx_ltrim(arg->data.str, sym->data.str); + } + + if (2 != token->opt) + zbx_variant_clear(&sym_val); + + zbx_variant_set_str(&value, zbx_strdup(NULL, arg->data.str)); + eval_function_return(token->opt, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_concat * + * * + * Purpose: evaluate concat() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_concat(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *str1, *str2, value; + char *strval; + + if (2 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + str1 = &output->values[output->values_num - 2]; + str2 = &output->values[output->values_num - 1]; + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, str1, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, str2, error)) + { + return FAIL; + } + + strval = zbx_strdup(NULL, str1->data.str); + zbx_variant_set_str(&value, zbx_strdcat(strval, str2->data.str)); + eval_function_return(2, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_insert * + * * + * Purpose: evaluate insert() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_insert(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *arg, *start, *len, *replacement, value; + char *strval, *p; + size_t str_alloc, str_len, sz, src_len; + + if (4 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + arg = &output->values[output->values_num - 4]; + start = &output->values[output->values_num - 3]; + len = &output->values[output->values_num - 2]; + replacement = &output->values[output->values_num - 1]; + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, start, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, len, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, replacement, error)) + { + return FAIL; + } + + src_len = zbx_strlen_utf8(arg->data.str); + + if (0 == start->data.ui64 || start->data.ui64 > src_len) + { + *error = zbx_dsprintf(*error, "invalid function second argument at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (src_len < start->data.ui64 + len->data.ui64) + { + *error = zbx_dsprintf(*error, "invalid function third argument at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + strval = zbx_strdup(NULL, arg->data.str); + p = zbx_strshift_utf8(strval, start->data.ui64 - 1); + sz = zbx_strlen_utf8_nchars(p, len->data.ui64); + + str_alloc = str_len = strlen(strval) + 1; + zbx_replace_mem_dyn(&strval, &str_alloc, &str_len, (size_t)(p - strval), sz, replacement->data.str, + strlen(replacement->data.str)); + + zbx_variant_set_str(&value, strval); + eval_function_return(4, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_replace * + * * + * Purpose: evaluate replace() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_replace(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *arg, *pattern, *replacement, value; + char *strval, *p; + size_t pattern_len, replacement_len; + + if (3 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + arg = &output->values[output->values_num - 3]; + pattern = &output->values[output->values_num - 2]; + replacement = &output->values[output->values_num - 1]; + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, pattern, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, replacement, error)) + { + return FAIL; + } + + strval = zbx_strdup(NULL, arg->data.str); + pattern_len = strlen(pattern->data.str); + + if (0 < pattern_len) + { + replacement_len = strlen(replacement->data.str); + + while (NULL != (p = strstr(strval, pattern->data.str))) + { + size_t str_alloc, str_len; + + str_alloc = str_len = strlen(strval) + 1; + zbx_replace_mem_dyn(&strval, &str_alloc, &str_len, (size_t)(p - strval), pattern_len, + replacement->data.str, replacement_len); + } + } + + zbx_variant_set_str(&value, strval); + eval_function_return(3, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_repeat * + * * + * Purpose: evaluate repeat() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_repeat(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *str, *num, value; + char *strval = NULL; + zbx_uint64_t i; + size_t len_utf8; + + if (2 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + str = &output->values[output->values_num - 2]; + num = &output->values[output->values_num - 1]; + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, str, error) || + SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, num, error)) + { + return FAIL; + } + + len_utf8 = zbx_strlen_utf8(str->data.str); + + if (num->data.ui64 * len_utf8 >= MAX_STRING_LEN) + { + *error = zbx_dsprintf(*error, "maximum allowed string length (%d) exceeded: " ZBX_FS_UI64, + MAX_STRING_LEN, num->data.ui64 * len_utf8); return FAIL; } - zbx_variant_set_ui64(&value, left->data.ui64 & right->data.ui64); + for (i = num->data.ui64; i > 0; i--) + strval = zbx_strdcat(strval, str->data.str); + + if (NULL == strval) + strval = zbx_strdup(NULL, ""); + + zbx_variant_set_str(&value, strval); eval_function_return(2, &value, output); return SUCCEED; @@ -1263,15 +1932,367 @@ static int eval_execute_function_bitand(const zbx_eval_context_t *ctx, const zbx /****************************************************************************** * * + * Function: eval_execute_function_bytelength * + * * + * Purpose: evaluate bytelength() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_bytelength(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *arg, value; + + if (1 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + arg = &output->values[output->values_num - 1]; + + if (SUCCEED == zbx_variant_convert(arg, ZBX_VARIANT_UI64)) + { + zbx_uint64_t byte = __UINT64_C(0xFF00000000000000); + int i; + + for (i = 8; i > 0; i--) + { + if (byte & arg->data.ui64) + break; + + byte = byte >> 8; + } + + zbx_variant_set_dbl(&value, i); + } + else if (SUCCEED != zbx_variant_convert(arg, ZBX_VARIANT_STR)) + { + *error = zbx_dsprintf(*error, "invalid function argument at \"%s\"", ctx->expression + token->loc.l); + return FAIL; + } + else + zbx_variant_set_dbl(&value, strlen(arg->data.str)); + + eval_function_return(1, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_bitlength * + * * + * Purpose: evaluate bitlength() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_bitlength(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *arg, value; + + if (1 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + arg = &output->values[output->values_num - 1]; + + if (SUCCEED == zbx_variant_convert(arg, ZBX_VARIANT_UI64)) + { + int i, bits; + + bits = sizeof(uint64_t) * 8; + + for (i = bits - 1; i >= 0; i--) + { + if (__UINT64_C(1) << i & arg->data.ui64) + break; + } + + zbx_variant_set_dbl(&value, ++i); + } + else if (SUCCEED != zbx_variant_convert(arg, ZBX_VARIANT_STR)) + { + *error = zbx_dsprintf(*error, "invalid function argument at \"%s\"", ctx->expression + token->loc.l); + return FAIL; + } + else + zbx_variant_set_dbl(&value, strlen(arg->data.str) * 8); + + eval_function_return(1, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_char * + * * + * Purpose: evaluate char() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_char(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *arg, value; + + if (1 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + arg = &output->values[output->values_num - 1]; + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_UI64, arg, error)) + return FAIL; + + if (255 < arg->data.ui64) + { + *error = zbx_dsprintf(*error, "function argument \"%s\" is out of allowed range at \"%s\"", + zbx_variant_value_desc(arg), ctx->expression + token->loc.l); + return FAIL; + } + + zbx_variant_set_str(&value, zbx_dsprintf(NULL, "%c", (char)arg->data.ui64)); + eval_function_return(1, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_ascii * + * * + * Purpose: evaluate ascii() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_ascii(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int ret; + zbx_variant_t *arg, value; + + if (1 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + arg = &output->values[output->values_num - 1]; + + if (SUCCEED != zbx_variant_convert(arg, ZBX_VARIANT_STR) || 0 > *arg->data.str) + { + *error = zbx_dsprintf(*error, "invalid function argument at \"%s\"", ctx->expression + token->loc.l); + return FAIL; + } + + zbx_variant_set_ui64(&value, (zbx_uint64_t)*arg->data.str); + eval_function_return(1, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_between * + * * + * Purpose: evaluate between() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_between(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int i, ret; + double between; + zbx_variant_t value; + + if (3 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_prepare_math_function_args(ctx, token, output, error))) + return ret; + + i = output->values_num - token->opt; + between = output->values[i++].data.dbl; + + if (output->values[i++].data.dbl <= between && between <= output->values[i].data.dbl) + zbx_variant_set_dbl(&value, 1); + else + zbx_variant_set_dbl(&value, 0); + + eval_function_return(3, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_function_in * + * * + * Purpose: evaluate in() function * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_function_in(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error) +{ + int i, arg_idx, found = 0, ret; + zbx_variant_t value, *arg, *ref_str = NULL; + double ref = 0; + + if (2 > token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_validate_function_args(ctx, token, output, error))) + return ret; + + zbx_variant_set_dbl(&value, 0); + + for (i = arg_idx = output->values_num - token->opt; i < output->values_num; i++) + { + zbx_variant_t val_copy; + + if (SUCCEED != variant_convert_suffixed_num(&val_copy, &output->values[i])) + { + zbx_variant_copy(&val_copy, &output->values[i]); + + if (SUCCEED != zbx_variant_convert(&val_copy, ZBX_VARIANT_DBL)) + { + zbx_variant_clear(&val_copy); + break; + } + } + + if (i == arg_idx) + { + ref = val_copy.data.dbl; + continue; + } + + if (0 == found && SUCCEED == zbx_double_compare(ref, val_copy.data.dbl)) + found = 1; + } + + if (i == output->values_num) + { + if (1 == found) + zbx_variant_set_dbl(&value, 1); + + goto out; + } + + for (i = arg_idx; i < output->values_num; i++) + { + arg = &output->values[i]; + + if (SUCCEED != eval_convert_function_arg(ctx, token, ZBX_VARIANT_STR, arg, error)) + return FAIL; + + if (i == arg_idx) + { + ref_str = arg; + continue; + } + + if (0 == strcmp(ref_str->data.str, arg->data.str)) + { + zbx_variant_set_dbl(&value, 1); + break; + } + } +out: + eval_function_return(token->opt, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * * Function: eval_execute_cb_function * * * * Purpose: evaluate function by calling custom callback (if configured) * * * - * Parameters: ctx - [IN] the evaluation context * - * token - [IN] the function token * - * functio_cb - [IN] the callback function * - * output - [IN/OUT] the output value stack * - * error - [OUT] the error message in the case of failure * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * function_cb - [IN] the callback function * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * * * * Return value: SUCCEED - the function was executed successfully * * FAIL - otherwise * @@ -1303,6 +2324,239 @@ static int eval_execute_cb_function(const zbx_eval_context_t *ctx, const zbx_eva return SUCCEED; } +#define ZBX_MATH_CONST_PI 3.141592653589793238463 +#define ZBX_MATH_CONST_E 2.7182818284590452354 +#define ZBX_MATH_RANDOM 0 + +static double eval_math_func_degrees(double radians) +{ + return radians * (180.0 / ZBX_MATH_CONST_PI); +} + +static double eval_math_func_radians(double degrees) +{ + return degrees * (ZBX_MATH_CONST_PI / 180); +} + +static double eval_math_func_cot(double x) +{ + return cos(x) / sin(x); +} + +static double eval_math_func_signum(double x) +{ + if (0 > x) + return -1; + + if (0 == x) + return 0; + + return 1; +} + +/****************************************************************************** + * * + * Function: eval_execute_math_function_single_param * + * * + * Purpose: evaluate mathematical function by calling passed function * + * with 1 double argument * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * func - [IN] the pointer to math function * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_math_function_single_param(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error, double (*func)(double)) +{ + int ret; + double result; + zbx_variant_t *arg, value; + + if (1 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_prepare_math_function_args(ctx, token, output, error))) + return ret; + + arg = &output->values[output->values_num - 1]; + + if (((log == func || log10 == func) && 0 >= arg->data.dbl) || (sqrt == func && 0 > arg->data.dbl) || + (eval_math_func_cot == func && 0 == arg->data.dbl)) + { + *error = zbx_dsprintf(*error, "invalid argument for function at \"%s\"", + ctx->expression + token->loc.l); + + return FAIL; + } + + result = func(arg->data.dbl); + + if (FP_ZERO != fpclassify(result) && FP_NORMAL != fpclassify(result)) + { + *error = zbx_dsprintf(*error, "calculation resulted in NaN or Infinity at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + zbx_variant_set_dbl(&value, result); + + eval_function_return(token->opt, &value, output); + + return SUCCEED; +} + +static double eval_math_func_round(double n, double decimal_points) +{ + double multiplier; + + multiplier = pow(10.0, decimal_points); + + return round(n * multiplier ) / multiplier; +} + +static double eval_math_func_truncate(double n, double decimal_points) +{ + double multiplier = 1; + + if (0 < decimal_points) + multiplier = pow(10, decimal_points); + + if (0 > n) + multiplier = -multiplier; + + return floor(multiplier * n) / multiplier; +} + +/****************************************************************************** + * * + * Function: eval_execute_math_function_double_param * + * * + * Purpose: evaluate mathematical function by calling passed function * + * with 2 double arguments * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * func - [IN] the pointer to math function * + * * + * Return value: SUCCEED - function evaluation succeeded * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int eval_execute_math_function_double_param(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error, double (*func)(double, double)) +{ + int ret; + double result; + zbx_variant_t *arg1, *arg2, value; + + if (2 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (UNKNOWN != (ret = eval_prepare_math_function_args(ctx, token, output, error))) + return ret; + + arg1 = &output->values[output->values_num - 2]; + arg2 = &output->values[output->values_num - 1]; + + if (((eval_math_func_round == func || eval_math_func_truncate == func) && (0 > arg2->data.dbl || + 0.0 != fmod(arg2->data.dbl, 1))) || (fmod == func && 0.0 == arg2->data.dbl)) + { + *error = zbx_dsprintf(*error, "invalid second argument for function at \"%s\"", + ctx->expression + token->loc.l); + + return FAIL; + } + + if (atan2 == func && 0.0 == arg1->data.dbl && 0.0 == arg2->data.dbl) + { + *error = zbx_dsprintf(*error, "undefined result for arguments (0,0) for function 'atan2' at \"%s\"", + ctx->expression + token->loc.l); + + return FAIL; + } + + result = func(arg1->data.dbl, arg2->data.dbl); + + if (FP_ZERO != fpclassify(result) && FP_NORMAL != fpclassify(result)) + { + *error = zbx_dsprintf(*error, "calculation resulted in NaN or Infinity at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + zbx_variant_set_dbl(&value, result); + + eval_function_return(token->opt, &value, output); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: eval_execute_math_function_return_value * + * * + * Purpose: evaluate mathematical function that returns constant value * + * * + * Parameters: ctx - [IN] the evaluation context * + * token - [IN] the function token * + * output - [IN/OUT] the output value stack * + * error - [OUT] the error message in the case of failure * + * value - [IN] the value to be returned * + * * + * Return value: SUCCEED - function evaluation succeeded * + * * + ******************************************************************************/ +static int eval_execute_math_return_value(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token, + zbx_vector_var_t *output, char **error, double value) +{ + zbx_variant_t ret_value; + + if (0 != token->opt) + { + *error = zbx_dsprintf(*error, "invalid number of arguments for function at \"%s\"", + ctx->expression + token->loc.l); + return FAIL; + } + + if (ZBX_MATH_RANDOM == value) + { + struct timespec ts; + + if (SUCCEED != clock_gettime(CLOCK_MONOTONIC, &ts)) + { + *error = zbx_strdup(*error, "failed to generate seed for random number generator"); + return FAIL; + } + else + { + srandom((unsigned int)(ts.tv_nsec ^ ts.tv_sec)); + zbx_variant_set_dbl(&ret_value, random()); + } + } + else + zbx_variant_set_dbl(&ret_value, value); + + eval_function_return(0, &ret_value, output); + + return SUCCEED; +} + /****************************************************************************** * * * Function: eval_execute_common_function * @@ -1351,7 +2605,121 @@ static int eval_execute_common_function(const zbx_eval_context_t *ctx, const zbx if (SUCCEED == eval_compare_token(ctx, &token->loc, "dayofmonth", ZBX_CONST_STRLEN("dayofmonth"))) return eval_execute_function_dayofmonth(ctx, token, output, error); if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitand", ZBX_CONST_STRLEN("bitand"))) - return eval_execute_function_bitand(ctx, token, output, error); + return eval_execute_function_bitwise(ctx, token, FUNCTION_OPTYPE_BIT_AND, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitor", ZBX_CONST_STRLEN("bitor"))) + return eval_execute_function_bitwise(ctx, token, FUNCTION_OPTYPE_BIT_OR, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitxor", ZBX_CONST_STRLEN("bitxor"))) + return eval_execute_function_bitwise(ctx, token, FUNCTION_OPTYPE_BIT_XOR, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitlshift", ZBX_CONST_STRLEN("bitlshift"))) + return eval_execute_function_bitwise(ctx, token, FUNCTION_OPTYPE_BIT_LSHIFT, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitrshift", ZBX_CONST_STRLEN("bitrshift"))) + return eval_execute_function_bitwise(ctx, token, FUNCTION_OPTYPE_BIT_RSHIFT, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitnot", ZBX_CONST_STRLEN("bitnot"))) + return eval_execute_function_bitnot(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "between", ZBX_CONST_STRLEN("between"))) + return eval_execute_function_between(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "in", ZBX_CONST_STRLEN("in"))) + return eval_execute_function_in(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "ascii", ZBX_CONST_STRLEN("ascii"))) + return eval_execute_function_ascii(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "char", ZBX_CONST_STRLEN("char"))) + return eval_execute_function_char(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "left", ZBX_CONST_STRLEN("left"))) + return eval_execute_function_left(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "right", ZBX_CONST_STRLEN("right"))) + return eval_execute_function_right(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "mid", ZBX_CONST_STRLEN("mid"))) + return eval_execute_function_mid(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "bitlength", ZBX_CONST_STRLEN("bitlength"))) + return eval_execute_function_bitlength(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "bytelength", ZBX_CONST_STRLEN("bytelength"))) + return eval_execute_function_bytelength(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "concat", ZBX_CONST_STRLEN("concat"))) + return eval_execute_function_concat(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "insert", ZBX_CONST_STRLEN("insert"))) + return eval_execute_function_insert(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "replace", ZBX_CONST_STRLEN("replace"))) + return eval_execute_function_replace(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "repeat", ZBX_CONST_STRLEN("repeat"))) + return eval_execute_function_repeat(ctx, token, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "ltrim", ZBX_CONST_STRLEN("ltrim"))) + return eval_execute_function_trim(ctx, token, FUNCTION_OPTYPE_TRIM_LEFT, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "rtrim", ZBX_CONST_STRLEN("rtrim"))) + return eval_execute_function_trim(ctx, token, FUNCTION_OPTYPE_TRIM_RIGHT, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "trim", ZBX_CONST_STRLEN("trim"))) + return eval_execute_function_trim(ctx, token, FUNCTION_OPTYPE_TRIM_ALL, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "cbrt", ZBX_CONST_STRLEN("cbrt"))) + return eval_execute_math_function_single_param(ctx, token, output, error, cbrt); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "ceil", ZBX_CONST_STRLEN("ceil"))) + return eval_execute_math_function_single_param(ctx, token, output, error, ceil); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "exp", ZBX_CONST_STRLEN("exp"))) + return eval_execute_math_function_single_param(ctx, token, output, error, exp); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "expm1", ZBX_CONST_STRLEN("expm1"))) + return eval_execute_math_function_single_param(ctx, token, output, error, expm1); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "floor", ZBX_CONST_STRLEN("floor"))) + return eval_execute_math_function_single_param(ctx, token, output, error, floor); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "signum", ZBX_CONST_STRLEN("signum"))) + return eval_execute_math_function_single_param(ctx, token, output, error, eval_math_func_signum); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "degrees", ZBX_CONST_STRLEN("degrees"))) + return eval_execute_math_function_single_param(ctx, token, output, error, eval_math_func_degrees); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "radians", ZBX_CONST_STRLEN("radians"))) + return eval_execute_math_function_single_param(ctx, token, output, error, eval_math_func_radians); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "acos", ZBX_CONST_STRLEN("acos"))) + return eval_execute_math_function_single_param(ctx, token, output, error, acos); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "asin", ZBX_CONST_STRLEN("asin"))) + return eval_execute_math_function_single_param(ctx, token, output, error, asin); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "atan", ZBX_CONST_STRLEN("atan"))) + return eval_execute_math_function_single_param(ctx, token, output, error, atan); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "cos", ZBX_CONST_STRLEN("cos"))) + return eval_execute_math_function_single_param(ctx, token, output, error, cos); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "cosh", ZBX_CONST_STRLEN("cosh"))) + return eval_execute_math_function_single_param(ctx, token, output, error, cosh); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "cot", ZBX_CONST_STRLEN("cot"))) + return eval_execute_math_function_single_param(ctx, token, output, error, eval_math_func_cot); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "sin", ZBX_CONST_STRLEN("sin"))) + return eval_execute_math_function_single_param(ctx, token, output, error, sin); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "sinh", ZBX_CONST_STRLEN("sinh"))) + return eval_execute_math_function_single_param(ctx, token, output, error, sinh); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "tan", ZBX_CONST_STRLEN("tan"))) + return eval_execute_math_function_single_param(ctx, token, output, error, tan); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "log", ZBX_CONST_STRLEN("log"))) + return eval_execute_math_function_single_param(ctx, token, output, error, log); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "log10", ZBX_CONST_STRLEN("log10"))) + return eval_execute_math_function_single_param(ctx, token, output, error, log10); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "sqrt", ZBX_CONST_STRLEN("sqrt"))) + return eval_execute_math_function_single_param(ctx, token, output, error, sqrt); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "power", ZBX_CONST_STRLEN("power"))) + return eval_execute_math_function_double_param(ctx, token, output, error, pow); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "round", ZBX_CONST_STRLEN("round"))) + return eval_execute_math_function_double_param(ctx, token, output, error, eval_math_func_round); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "mod", ZBX_CONST_STRLEN("mod"))) + return eval_execute_math_function_double_param(ctx, token, output, error, fmod); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "truncate", ZBX_CONST_STRLEN("truncate"))) + return eval_execute_math_function_double_param(ctx, token, output, error, eval_math_func_truncate); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "atan2", ZBX_CONST_STRLEN("atan2"))) + return eval_execute_math_function_double_param(ctx, token, output, error, atan2); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "pi", ZBX_CONST_STRLEN("pi"))) + return eval_execute_math_return_value(ctx, token, output, error, ZBX_MATH_CONST_PI); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "e", ZBX_CONST_STRLEN("e"))) + return eval_execute_math_return_value(ctx, token, output, error, ZBX_MATH_CONST_E); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "rand", ZBX_CONST_STRLEN("rand"))) + return eval_execute_math_return_value(ctx, token, output, error, ZBX_MATH_RANDOM); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "kurtosis", ZBX_CONST_STRLEN("kurtosis"))) + return eval_execute_statistical_function(ctx, token, zbx_eval_calc_kurtosis, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "mad", ZBX_CONST_STRLEN("mad"))) + return eval_execute_statistical_function(ctx, token, zbx_eval_calc_mad, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "skewness", ZBX_CONST_STRLEN("skewness"))) + return eval_execute_statistical_function(ctx, token, zbx_eval_calc_skewness, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "stddevpop", ZBX_CONST_STRLEN("stddevpop"))) + return eval_execute_statistical_function(ctx, token, zbx_eval_calc_stddevpop, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "stddevsamp", ZBX_CONST_STRLEN("stddevsamp"))) + return eval_execute_statistical_function(ctx, token, zbx_eval_calc_stddevsamp, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "sumofsquares", ZBX_CONST_STRLEN("sumofsquares"))) + return eval_execute_statistical_function(ctx, token, zbx_eval_calc_sumofsquares, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "varpop", ZBX_CONST_STRLEN("varpop"))) + return eval_execute_statistical_function(ctx, token, zbx_eval_calc_varpop, output, error); + if (SUCCEED == eval_compare_token(ctx, &token->loc, "varsamp", ZBX_CONST_STRLEN("varsamp"))) + return eval_execute_statistical_function(ctx, token, zbx_eval_calc_varsamp, output, error); if (NULL != ctx->common_func_cb) return eval_execute_cb_function(ctx, token, ctx->common_func_cb, output, error); diff --git a/src/libs/zbxeval/misc.c b/src/libs/zbxeval/misc.c index 9f6b86fb14c..94587b0fc77 100644 --- a/src/libs/zbxeval/misc.c +++ b/src/libs/zbxeval/misc.c @@ -767,8 +767,8 @@ void zbx_eval_get_functionids(zbx_eval_context_t *ctx, zbx_vector_uint64_t *func * * * Function: zbx_eval_get_functionids_ordered * * * - * Purpose: get functionids from parsed expression in the order as they * - * were written + * Purpose: get functionids from parsed expression in the order they are * + * written * * * * Parameters: ctx - [IN] the evaluation context * * functionids - [OUT] the extracted functionids * diff --git a/src/libs/zbxeval/parse.c b/src/libs/zbxeval/parse.c index 6a2e4c7e561..db41384dfb0 100644 --- a/src/libs/zbxeval/parse.c +++ b/src/libs/zbxeval/parse.c @@ -566,7 +566,7 @@ static int eval_parse_function_token(zbx_eval_context_t *ctx, size_t pos, zbx_ev { const char *ptr = ctx->expression + pos; - while (0 != isalpha((unsigned char)*ptr) || '_' == *ptr) + while (0 != isalpha((unsigned char)*ptr) || '_' == *ptr || 0 != isdigit((unsigned char)*ptr)) ptr++; if ('(' == *ptr) diff --git a/src/libs/zbxserver/evalfunc.c b/src/libs/zbxserver/evalfunc.c index a03303c8a9d..0ceabb17da6 100644 --- a/src/libs/zbxserver/evalfunc.c +++ b/src/libs/zbxserver/evalfunc.c @@ -25,6 +25,7 @@ #include "evalfunc.h" #include "zbxregexp.h" #include "zbxtrends.h" +#include "../zbxalgo/vectorimpl.h" typedef enum { @@ -40,6 +41,26 @@ typedef enum } zbx_value_type_t; +#define ZBX_VALUEMAP_STRING_LEN 64 + +#define ZBX_VALUEMAP_TYPE_MATCH 0 +#define ZBX_VALUEMAP_TYPE_GREATER_OR_EQUAL 1 +#define ZBX_VALUEMAP_TYPE_LESS_OR_EQUAL 2 +#define ZBX_VALUEMAP_TYPE_RANGE 3 +#define ZBX_VALUEMAP_TYPE_REGEX 4 +#define ZBX_VALUEMAP_TYPE_DEFAULT 5 + +typedef struct +{ + char value[ZBX_VALUEMAP_STRING_LEN]; + char newvalue[ZBX_VALUEMAP_STRING_LEN]; + int type; +} +zbx_valuemaps_t; + +ZBX_PTR_VECTOR_DECL(valuemaps_ptr, zbx_valuemaps_t *) +ZBX_PTR_VECTOR_IMPL(valuemaps_ptr, zbx_valuemaps_t *) + static const char *zbx_type_string(zbx_value_type_t type) { switch (type) @@ -3442,6 +3463,165 @@ static void add_value_suffix(char *value, size_t max_len, const char *units, uns zabbix_log(LOG_LEVEL_DEBUG, "End of %s() value:'%s'", __func__, value); } +static void zbx_valuemaps_free(zbx_valuemaps_t *valuemap) +{ + zbx_free(valuemap); +} + +/****************************************************************************** + * * + * Function: evaluate_value_by_map * + * * + * Purpose: replace value by mapping value * + * * + * Parameters: value - value for replacing * + * max_len - maximal length of output value * + * valuemaps - vector of values mapped * + * value_type - type of input value * + * * + * Return value: SUCCEED - evaluated successfully, value contains new value * + * FAIL - evaluation failed, value contains old value * + * * + ******************************************************************************/ +static int evaluate_value_by_map(char *value, size_t max_len, zbx_vector_valuemaps_ptr_t *valuemaps, + unsigned char value_type) +{ + char *value_tmp; + int i, ret = FAIL; + double input_value; + zbx_valuemaps_t *valuemap; + + for (i = 0; i < valuemaps->values_num; i++) + { + char *pattern; + int match; + zbx_vector_ptr_t regexps; + + valuemap = (zbx_valuemaps_t *)valuemaps->values[i]; + + if (ZBX_VALUEMAP_TYPE_MATCH == valuemap->type) + { + if (ITEM_VALUE_TYPE_STR != value_type) + { + double num1, num2; + + if (ZBX_INFINITY != (num1 = evaluate_string_to_double(value)) && + ZBX_INFINITY != (num2 = evaluate_string_to_double(valuemap->value)) && + SUCCEED == zbx_double_compare(num1, num2)) + { + goto map_value; + } + } + else if (0 == strcmp(valuemap->value, value)) + goto map_value; + } + + if (ITEM_VALUE_TYPE_STR == value_type && ZBX_VALUEMAP_TYPE_REGEX == valuemap->type) + { + zbx_vector_ptr_create(®exps); + + pattern = valuemap->value; + + match = regexp_match_ex(®exps, value, pattern, ZBX_CASE_SENSITIVE); + + zbx_regexp_clean_expressions(®exps); + zbx_vector_ptr_destroy(®exps); + + if (ZBX_REGEXP_MATCH == match) + goto map_value; + } + + if (ITEM_VALUE_TYPE_STR != value_type && + ZBX_INFINITY != (input_value = evaluate_string_to_double(value))) + { + double min, max; + + if (ZBX_VALUEMAP_TYPE_LESS_OR_EQUAL == valuemap->type && + ZBX_INFINITY != (max = evaluate_string_to_double(valuemap->value))) + { + if (input_value <= max) + goto map_value; + } + else if (ZBX_VALUEMAP_TYPE_GREATER_OR_EQUAL == valuemap->type && + ZBX_INFINITY != (min = evaluate_string_to_double(valuemap->value))) + { + if (input_value >= min) + goto map_value; + } + else if (ZBX_VALUEMAP_TYPE_RANGE == valuemap->type) + { + int num, j; + char *input_ptr; + + input_ptr = valuemap->value; + + zbx_trim_str_list(input_ptr, ','); + zbx_trim_str_list(input_ptr, '-'); + num = num_param(input_ptr); + + for (j = 0; j < num; j++) + { + int found = 0; + char *ptr, *range_str; + + range_str = ptr = get_param_dyn(input_ptr, j + 1, NULL); + + if (1 < strlen(ptr) && '-' == *ptr) + ptr++; + + while (NULL != (ptr = strchr(ptr, '-'))) + { + if (ptr > range_str && 'e' != ptr[-1] && 'E' != ptr[-1]) + break; + ptr++; + } + + if (NULL == ptr) + { + min = evaluate_string_to_double(range_str); + found = ZBX_INFINITY != min && SUCCEED == zbx_double_compare(input_value, min); + } + else + { + *ptr = '\0'; + min = evaluate_string_to_double(range_str); + max = evaluate_string_to_double(ptr + 1); + if (ZBX_INFINITY != min && ZBX_INFINITY != max && + input_value >= min && input_value <= max) + { + found = 1; + } + } + + zbx_free(range_str); + + if (0 != found) + goto map_value; + } + } + } + } + + for (i = 0; i < valuemaps->values_num; i++) + { + valuemap = (zbx_valuemaps_t *)valuemaps->values[i]; + + if (ZBX_VALUEMAP_TYPE_DEFAULT == valuemap->type) + goto map_value; + } +map_value: + if (i < valuemaps->values_num) + { + value_tmp = zbx_dsprintf(NULL, "%s (%s)", valuemap->newvalue, value); + zbx_strlcpy_utf8(value, value_tmp, max_len); + zbx_free(value_tmp); + + ret = SUCCEED; + } + + return ret; +} + /****************************************************************************** * * * Function: replace_value_by_map * @@ -3449,44 +3629,53 @@ static void add_value_suffix(char *value, size_t max_len, const char *units, uns * Purpose: replace value by mapping value * * * * Parameters: value - value for replacing * + * max_len - maximal length of output value * * valuemapid - index of value map * + * value_type - type of input value * * * * Return value: SUCCEED - evaluated successfully, value contains new value * * FAIL - evaluation failed, value contains old value * * * ******************************************************************************/ -static int replace_value_by_map(char *value, size_t max_len, zbx_uint64_t valuemapid) +static int replace_value_by_map(char *value, size_t max_len, zbx_uint64_t valuemapid, unsigned char value_type) { - DB_RESULT result; - DB_ROW row; - char *value_esc, *value_tmp; - int ret = FAIL; + int ret = FAIL; + DB_RESULT result; + DB_ROW row; + zbx_valuemaps_t *valuemap; + zbx_vector_valuemaps_ptr_t valuemaps; zabbix_log(LOG_LEVEL_DEBUG, "In %s() value:'%s' valuemapid:" ZBX_FS_UI64, __func__, value, valuemapid); if (0 == valuemapid) goto clean; - value_esc = DBdyn_escape_string(value); + zbx_vector_valuemaps_ptr_create(&valuemaps); + result = DBselect( - "select newvalue" + "select value,newvalue,type" " from valuemap_mapping" " where valuemapid=" ZBX_FS_UI64 - " and value" ZBX_SQL_STRCMP, - valuemapid, ZBX_SQL_STRVAL_EQ(value_esc)); - zbx_free(value_esc); + " order by sortorder asc", + valuemapid); - if (NULL != (row = DBfetch(result)) && FAIL == DBis_null(row[0])) + while (NULL != (row = DBfetch(result))) { - del_zeros(row[0]); - - value_tmp = zbx_dsprintf(NULL, "%s (%s)", row[0], value); - zbx_strlcpy_utf8(value, value_tmp, max_len); - zbx_free(value_tmp); + del_zeros(row[1]); - ret = SUCCEED; + valuemap = (zbx_valuemaps_t *)zbx_malloc(NULL, sizeof(zbx_valuemaps_t)); + zbx_strlcpy_utf8(valuemap->value, row[0], ZBX_VALUEMAP_STRING_LEN); + zbx_strlcpy_utf8(valuemap->newvalue, row[1], ZBX_VALUEMAP_STRING_LEN); + valuemap->type = atoi(row[2]); + zbx_vector_valuemaps_ptr_append(&valuemaps, valuemap); } + DBfree_result(result); + + ret = evaluate_value_by_map(value, max_len, &valuemaps, value_type); + + zbx_vector_valuemaps_ptr_clear_ext(&valuemaps, zbx_valuemaps_free); + zbx_vector_valuemaps_ptr_destroy(&valuemaps); clean: zabbix_log(LOG_LEVEL_DEBUG, "End of %s() value:'%s'", __func__, value); @@ -3513,13 +3702,13 @@ void zbx_format_value(char *value, size_t max_len, zbx_uint64_t valuemapid, switch (value_type) { case ITEM_VALUE_TYPE_STR: - replace_value_by_map(value, max_len, valuemapid); + replace_value_by_map(value, max_len, valuemapid, value_type); break; case ITEM_VALUE_TYPE_FLOAT: del_zeros(value); ZBX_FALLTHROUGH; case ITEM_VALUE_TYPE_UINT64: - if (SUCCEED != replace_value_by_map(value, max_len, valuemapid)) + if (SUCCEED != replace_value_by_map(value, max_len, valuemapid, value_type)) add_value_suffix(value, max_len, units, value_type); break; default: @@ -3662,3 +3851,7 @@ int zbx_evaluatable_for_notsupported(const char *fn) return FAIL; } + +#ifdef HAVE_TESTS +# include "../../../tests/libs/zbxserver/valuemaps_test.c" +#endif diff --git a/src/libs/zbxserver/evalfunc2.c b/src/libs/zbxserver/evalfunc2.c index 9b0a16f26eb..7872b897b26 100644 --- a/src/libs/zbxserver/evalfunc2.c +++ b/src/libs/zbxserver/evalfunc2.c @@ -585,6 +585,93 @@ out: return ret; } +static int history_record_float_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2) +{ + ZBX_RETURN_IF_NOT_EQUAL(d1->value.dbl, d2->value.dbl); + + return 0; +} + +static int history_record_uint64_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2) +{ + ZBX_RETURN_IF_NOT_EQUAL(d1->value.ui64, d2->value.ui64); + + return 0; +} + +static int history_record_str_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2) +{ + return strcmp(d1->value.str, d2->value.str); +} + +static int history_record_log_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2) +{ + int value_match; + + if (0 != (value_match = strcmp(d1->value.log->value, d2->value.log->value))) + return value_match; + + if (NULL != d1->value.log->source && NULL != d2->value.log->source) + return strcmp(d1->value.log->source, d2->value.log->source); + + if (NULL != d2->value.log->source) + return -1; + + if (NULL != d1->value.log->source) + return 1; + + return 0; +} + +/* specialized versions of zbx_vector_history_record_*_uniq() because */ +/* standard versions do not release memory occupied by duplicate elements */ + +static void zbx_vector_history_record_str_uniq(zbx_vector_history_record_t *vector, zbx_compare_func_t compare_func) +{ + if (2 <= vector->values_num) + { + int i = 0, j = 1; + + while (j < vector->values_num) + { + if (0 != compare_func(&vector->values[i], &vector->values[j])) + { + i++; + j++; + } + else + { + zbx_free(vector->values[j].value.str); + zbx_vector_history_record_remove(vector, j); + } + } + } +} + +static void zbx_vector_history_record_log_uniq(zbx_vector_history_record_t *vector, zbx_compare_func_t compare_func) +{ + if (2 <= vector->values_num) + { + int i = 0, j = 1; + + while (j < vector->values_num) + { + if (0 != compare_func(&vector->values[i], &vector->values[j])) + { + i++; + j++; + } + else + { + zbx_free(vector->values[j].value.log->source); + zbx_free(vector->values[j].value.log->value); + zbx_free(vector->values[j].value.log); + zbx_vector_history_record_remove(vector, j); + } + } + } +} + #define OP_UNKNOWN -1 #define OP_EQ 0 #define OP_NE 1 @@ -693,6 +780,10 @@ static void count_one_str(int *count, int op, const char *value, const char *pat } } +/* flags for evaluate_COUNT() */ +#define COUNT_ALL 0 +#define COUNT_UNIQUE 1 + /****************************************************************************** * * * Function: evaluate_COUNT * @@ -713,6 +804,8 @@ static void count_one_str(int *count, int op, const char *value, const char *pat * ts - [IN] the function evaluation time * * limit - [IN] the limit of counted values, will return * * when the limit is reached * + * unique - [IN] COUNT_ALL - count all values, * + * COUNT_UNIQUE - count unique values * * error - [OUT] the error message * * * * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* @@ -720,7 +813,7 @@ static void count_one_str(int *count, int op, const char *value, const char *pat * * ******************************************************************************/ static int evaluate_COUNT(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, - int limit, char **error) + int limit, int unique, char **error) { int arg1, op = OP_UNKNOWN, numeric_search, nparams, count = 0, i, ret = FAIL; int seconds = 0, nvalues = 0, time_shift; @@ -916,6 +1009,36 @@ static int evaluate_COUNT(zbx_variant_t *value, DC_ITEM *item, const char *param goto out; } + if (COUNT_UNIQUE == unique) + { + switch (item->value_type) + { + case ITEM_VALUE_TYPE_UINT64: + zbx_vector_history_record_sort(&values, + (zbx_compare_func_t)history_record_uint64_compare); + zbx_vector_history_record_uniq(&values, + (zbx_compare_func_t)history_record_uint64_compare); + break; + case ITEM_VALUE_TYPE_FLOAT: + zbx_vector_history_record_sort(&values, + (zbx_compare_func_t)history_record_float_compare); + zbx_vector_history_record_uniq(&values, + (zbx_compare_func_t)history_record_float_compare); + break; + case ITEM_VALUE_TYPE_LOG: + zbx_vector_history_record_sort(&values, + (zbx_compare_func_t)history_record_log_compare); + zbx_vector_history_record_log_uniq(&values, + (zbx_compare_func_t)history_record_log_compare); + break; + default: + zbx_vector_history_record_sort(&values, + (zbx_compare_func_t)history_record_str_compare); + zbx_vector_history_record_str_uniq(&values, + (zbx_compare_func_t)history_record_str_compare); + } + } + /* skip counting values one by one if both pattern and operator are empty or "" is searched in text values */ if ((NULL != pattern && '\0' != *pattern) || (NULL != operator && '\0' != *operator && OP_LIKE != op && OP_REGEXP != op && OP_IREGEXP != op)) @@ -1022,7 +1145,7 @@ out: ******************************************************************************/ static int evaluate_SUM(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error) { - int nparams, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift; + int arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift; zbx_value_type_t arg1_type; zbx_vector_history_record_t values; history_value_t result; @@ -1038,7 +1161,7 @@ static int evaluate_SUM(zbx_variant_t *value, DC_ITEM *item, const char *paramet goto out; } - if (1 != (nparams = num_param(parameters))) + if (1 != num_param(parameters)) { *error = zbx_strdup(*error, "invalid number of parameters"); goto out; @@ -1111,7 +1234,7 @@ out: ******************************************************************************/ static int evaluate_AVG(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error) { - int nparams, arg1, ret = FAIL, i, seconds = 0, nvalues = 0, time_shift; + int arg1, ret = FAIL, i, seconds = 0, nvalues = 0, time_shift; zbx_value_type_t arg1_type; zbx_vector_history_record_t values; zbx_timespec_t ts_end = *ts; @@ -1126,7 +1249,7 @@ static int evaluate_AVG(zbx_variant_t *value, DC_ITEM *item, const char *parame goto out; } - if (1 != (nparams = num_param(parameters))) + if (1 != num_param(parameters)) { *error = zbx_strdup(*error, "invalid number of parameters"); goto out; @@ -1240,7 +1363,7 @@ static int evaluate_LAST(zbx_variant_t *value, DC_ITEM *item, const char *parame ******************************************************************************/ static int evaluate_MIN(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error) { - int nparams, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift; + int arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift; zbx_value_type_t arg1_type; zbx_vector_history_record_t values; zbx_timespec_t ts_end = *ts; @@ -1255,7 +1378,7 @@ static int evaluate_MIN(zbx_variant_t *value, DC_ITEM *item, const char *paramet goto out; } - if (1 != (nparams = num_param(parameters))) + if (1 != num_param(parameters)) { *error = zbx_strdup(*error, "invalid number of parameters"); goto out; @@ -1340,7 +1463,7 @@ out: ******************************************************************************/ static int evaluate_MAX(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error) { - int nparams, arg1, ret = FAIL, i, seconds = 0, nvalues = 0, time_shift; + int arg1, ret = FAIL, i, seconds = 0, nvalues = 0, time_shift; zbx_value_type_t arg1_type; zbx_vector_history_record_t values; zbx_timespec_t ts_end = *ts; @@ -1355,7 +1478,7 @@ static int evaluate_MAX(zbx_variant_t *value, DC_ITEM *item, const char *paramet goto out; } - if (1 != (nparams = num_param(parameters))) + if (1 != num_param(parameters)) { *error = zbx_strdup(*error, "invalid number of parameters"); goto out; @@ -1426,20 +1549,6 @@ out: return ret; } -static int __history_record_float_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2) -{ - ZBX_RETURN_IF_NOT_EQUAL(d1->value.dbl, d2->value.dbl); - - return 0; -} - -static int __history_record_uint64_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2) -{ - ZBX_RETURN_IF_NOT_EQUAL(d1->value.ui64, d2->value.ui64); - - return 0; -} - /****************************************************************************** * * * Function: evaluate_PERCENTILE * @@ -1458,7 +1567,7 @@ static int __history_record_uint64_compare(const zbx_history_record_t *d1, const static int evaluate_PERCENTILE(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error) { - int nparams, arg1, time_shift, ret = FAIL, seconds = 0, nvalues = 0; + int arg1, time_shift, ret = FAIL, seconds = 0, nvalues = 0; zbx_value_type_t arg1_type; double percentage; zbx_vector_history_record_t values; @@ -1474,7 +1583,7 @@ static int evaluate_PERCENTILE(zbx_variant_t *value, DC_ITEM *item, const char goto out; } - if (2 != (nparams = num_param(parameters))) + if (2 != num_param(parameters)) { *error = zbx_strdup(*error, "invalid number of parameters"); goto out; @@ -1520,9 +1629,9 @@ static int evaluate_PERCENTILE(zbx_variant_t *value, DC_ITEM *item, const char int index; if (ITEM_VALUE_TYPE_FLOAT == item->value_type) - zbx_vector_history_record_sort(&values, (zbx_compare_func_t)__history_record_float_compare); + zbx_vector_history_record_sort(&values, (zbx_compare_func_t)history_record_float_compare); else - zbx_vector_history_record_sort(&values, (zbx_compare_func_t)__history_record_uint64_compare); + zbx_vector_history_record_sort(&values, (zbx_compare_func_t)history_record_uint64_compare); if (0 == percentage) index = 1; @@ -1816,14 +1925,11 @@ out: * * * Parameters: value - dynamic buffer * * item - item (performance metric) * - * parameters - up to 3 comma-separated fields: * + * parameters - to 2 comma-separated fields: * * (1) same as the 1st parameter for function * * evaluate_LAST() (see documentation of * * trigger function last()), * * (2) mask to bitwise AND with (mandatory), * - * (3) same as the 2nd parameter for function * - * evaluate_LAST() (see documentation of * - * trigger function last()). * * * * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* * FAIL - failed to evaluate function * @@ -1833,7 +1939,7 @@ static int evaluate_BITAND(zbx_variant_t *value, DC_ITEM *item, const char *para char **error) { char *last_parameters = NULL; - int nparams, ret = FAIL; + int ret = FAIL; zbx_uint64_t mask; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); @@ -1844,7 +1950,7 @@ static int evaluate_BITAND(zbx_variant_t *value, DC_ITEM *item, const char *para goto clean; } - if (2 < (nparams = num_param(parameters))) + if (2 < num_param(parameters)) { *error = zbx_strdup(*error, "invalid number of parameters"); goto clean; @@ -2269,6 +2375,219 @@ out: return ret; } +static int validate_params_and_get_data(DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, + zbx_vector_history_record_t *values, char **error) +{ + int arg1, seconds = 0, nvalues = 0, time_shift; + zbx_value_type_t arg1_type; + zbx_timespec_t ts_end = *ts; + + if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + return FAIL; + } + + if (1 != num_param(parameters)) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + return FAIL; + } + + if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) || + ZBX_VALUE_NONE == arg1_type) + { + *error = zbx_strdup(*error, "invalid parameter"); + return FAIL; + } + + ts_end.sec -= time_shift; + + switch (arg1_type) + { + case ZBX_VALUE_SECONDS: + seconds = arg1; + break; + case ZBX_VALUE_NVALUES: + nvalues = arg1; + break; + case ZBX_VALUE_NONE: + default: + *error = zbx_strdup(*error, "invalid type of first argument"); + THIS_SHOULD_NEVER_HAPPEN; + return FAIL; + } + + if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, values, seconds, nvalues, &ts_end)) + { + *error = zbx_strdup(*error, "cannot get values from value cache"); + return FAIL; + } + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: evaluate_FIRST * + * * + * Purpose: evaluate function 'first' for the item * + * * + * Parameters: value - dynamic buffer * + * item - item (performance metric) * + * parameters - Nth first value and time shift (optional) * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_FIRST(zbx_variant_t *value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, + char **error) +{ + int arg1 = 1, ret = FAIL, seconds = 0, time_shift; + zbx_value_type_t arg1_type = ZBX_VALUE_NVALUES; + zbx_vector_history_record_t values; + zbx_timespec_t ts_end = *ts; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_history_record_vector_create(&values); + + if (1 != num_param(parameters)) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift)) + { + *error = zbx_strdup(*error, "invalid parameter"); + goto out; + } + + switch (arg1_type) + { + case ZBX_VALUE_SECONDS: + seconds = arg1; + break; + case ZBX_VALUE_NONE: + *error = zbx_strdup(*error, "the first argument is not specified"); + goto out; + case ZBX_VALUE_NVALUES: + *error = zbx_strdup(*error, "the first argument cannot be number of value"); + goto out; + default: + *error = zbx_strdup(*error, "invalid type of first argument"); + THIS_SHOULD_NEVER_HAPPEN; + goto out; + } + + if (0 >= arg1) + { + *error = zbx_strdup(*error, "the first argument must be greater than 0"); + goto out; + } + + ts_end.sec -= time_shift; + + if (SUCCEED == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, 0, &ts_end)) + { + if (0 < values.values_num) + { + zbx_history_value2variant(&values.values[values.values_num - 1].value, item->value_type, value); + ret = SUCCEED; + } + else + { + *error = zbx_strdup(*error, "not enough data"); + goto out; + } + } + else + *error = zbx_strdup(*error, "cannot get values from value cache"); +out: + zbx_history_record_vector_destroy(&values, item->value_type); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +static void history_to_dbl_vector(const zbx_history_record_t *v, int n, unsigned char value_type, + zbx_vector_dbl_t *values) +{ + int i; + + zbx_vector_dbl_reserve(values, (size_t)n); + + if (ITEM_VALUE_TYPE_FLOAT == value_type) + { + for (i = 0; i < n; i++) + zbx_vector_dbl_append(values, v[i].value.dbl); + } + else + { + for (i = 0; i < n; i++) + zbx_vector_dbl_append(values, (double)v[i].value.ui64); + } +} + +/****************************************************************************** + * * + * Function: evaluate_statistical_func * + * * + * Purpose: common operations for aggregate function calculation * + * * + * Parameters: value - [OUT] result * + * item - [IN] item (performance metric) * + * parameters - [IN] number of seconds/values and time shift * + * (optional) * + * ts - [IN] time shift * + * stat_func - [IN] pointer to aggregate function to be called * + * min_values - [IN] minimum data values required * + * error - [OUT] the error message in the case of failure * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_statistical_func(zbx_variant_t *value, DC_ITEM *item, const char *parameters, + const zbx_timespec_t *ts, zbx_statistical_func_t stat_func, int min_values, char **error) +{ + int ret = FAIL; + zbx_vector_history_record_t values; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_history_record_vector_create(&values); + + if (SUCCEED != validate_params_and_get_data(item, parameters, ts, &values, error)) + goto out; + + if (min_values <= values.values_num) + { + zbx_vector_dbl_t values_dbl; + double result; + + zbx_vector_dbl_create(&values_dbl); + + history_to_dbl_vector(values.values, values.values_num, item->value_type, &values_dbl); + + if (SUCCEED == (ret = stat_func(&values_dbl, &result, error))) + zbx_variant_set_dbl(value, result); + + zbx_vector_dbl_destroy(&values_dbl); + } + else + *error = zbx_strdup(*error, "not enough data"); +out: + zbx_history_record_vector_destroy(&values, item->value_type); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + /****************************************************************************** * * * Function: evaluate_function * @@ -2317,7 +2636,11 @@ int evaluate_function2(zbx_variant_t *value, DC_ITEM *item, const char *function } else if (0 == strcmp(function, "count")) { - ret = evaluate_COUNT(value, item, parameter, ts, ZBX_MAX_UINT31_1, error); + ret = evaluate_COUNT(value, item, parameter, ts, ZBX_MAX_UINT31_1, COUNT_ALL, error); + } + else if (0 == strcmp(function, "countunique")) + { + ret = evaluate_COUNT(value, item, parameter, ts, ZBX_MAX_UINT31_1, COUNT_UNIQUE, error); } else if (0 == strcmp(function, "nodata")) { @@ -2329,7 +2652,7 @@ int evaluate_function2(zbx_variant_t *value, DC_ITEM *item, const char *function } else if (0 == strcmp(function, "find")) { - ret = evaluate_COUNT(value, item, parameter, ts, 1, error); + ret = evaluate_COUNT(value, item, parameter, ts, 1, COUNT_ALL, error); } else if (0 == strcmp(function, "fuzzytime")) { @@ -2363,6 +2686,42 @@ int evaluate_function2(zbx_variant_t *value, DC_ITEM *item, const char *function { ret = evaluate_TREND(value, item, function + 5, parameter, ts, error); } + else if (0 == strcmp(function, "first")) + { + ret = evaluate_FIRST(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "kurtosis")) + { + ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_kurtosis, 1, error); + } + else if (0 == strcmp(function, "mad")) + { + ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_mad, 1, error); + } + else if (0 == strcmp(function, "skewness")) + { + ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_skewness, 1, error); + } + else if (0 == strcmp(function, "stddevpop")) + { + ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_stddevpop, 1, error); + } + else if (0 == strcmp(function, "stddevsamp")) + { + ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_stddevsamp, 2, error); + } + else if (0 == strcmp(function, "sumofsquares")) + { + ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_sumofsquares, 1, error); + } + else if (0 == strcmp(function, "varpop")) + { + ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_varpop, 1, error); + } + else if (0 == strcmp(function, "varsamp")) + { + ret = evaluate_statistical_func(value, item, parameter, ts, zbx_eval_calc_varsamp, 2, error); + } else { *error = zbx_strdup(*error, "function is not supported"); @@ -2390,10 +2749,15 @@ int evaluate_function2(zbx_variant_t *value, DC_ITEM *item, const char *function ******************************************************************************/ int zbx_is_trigger_function(const char *name, size_t len) { - char *functions[] = {"last", "min", "max", "avg", "sum", "percentile", "count", "nodata", "change", "find", - "fuzzytime", "logeventid", "logseverity", "logsource", "bitand", "forecast", "timeleft", - "trendavg", "trendcount", "trendmax", "trendmin", "trendsum", - NULL}; + char *functions[] = {"last", "min", "max", "avg", "sum", "percentile", "count", "countunique", "nodata", + "change", "find", "fuzzytime", "logeventid", "logseverity", "logsource", "bitand", "forecast", + "timeleft", "trendavg", "trendcount", "trendmax", "trendmin", "trendsum", "abs", "cbrt", + "ceil", "exp", "floor", "log", "log10", "power", "round", "rand", "signum", "sqrt", "truncate", + "acos", "asin", "atan", "cos", "cosh", "cot", "sin", "sinh", "tan", "degrees", "radians", "mod", + "pi", "e", "expm1", "atan2", "first", "kurtosis", "mad", "skewness", "stddevpop", "stddevsamp", + "sumofsquares", "varpop", "varsamp", "ascii", "bitlength", "char", "concat", "insert", "lcase", + "left", "ltrim", "bytelength", "repeat", "replace", "right", "rtrim", "mid", "trim", "between", + "in", "bitor", "bitxor", "bitnot", "bitlshift", "bitrshift", NULL}; char **ptr; for (ptr = functions; NULL != *ptr; ptr++) diff --git a/src/libs/zbxserver/expression_eval.c b/src/libs/zbxserver/expression_eval.c index f6181fefedd..6c24c435e33 100644 --- a/src/libs/zbxserver/expression_eval.c +++ b/src/libs/zbxserver/expression_eval.c @@ -437,7 +437,12 @@ static void expression_get_item_candidates(zbx_expression_eval_t *eval, const zb if (0 != (query->flags & ZBX_ITEM_QUERY_KEY_SOME)) { init_request(&pattern); - parse_item_key(query->ref.key, &pattern); + if (SUCCEED != parse_item_key(query->ref.key, &pattern)) + { + THIS_SHOULD_NEVER_HAPPEN; + zbx_free(sql); + return; + } zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ",i.key_"); } @@ -515,7 +520,7 @@ static void expression_get_item_candidates(zbx_expression_eval_t *eval, const zb group->hostids.values_num); } else - zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " 0"); + zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " 1=0"); last_pos = token.loc.r + 1; pos = token.loc.r; diff --git a/src/zabbix_server/dbsyncer/dbsyncer.c b/src/zabbix_server/dbsyncer/dbsyncer.c index fd101257343..705a9d494ba 100644 --- a/src/zabbix_server/dbsyncer/dbsyncer.c +++ b/src/zabbix_server/dbsyncer/dbsyncer.c @@ -52,18 +52,19 @@ static void zbx_db_flush_timer_queue(void) if (0 != persistent_timers.values_num) { - zbx_db_insert_prepare(&db_insert, "trigger_queue", "objectid", "type", "clock", "ns", NULL); + zbx_db_insert_prepare(&db_insert, "trigger_queue", "trigger_queueid", "objectid", "type", "clock", "ns", NULL); for (i = 0; i < persistent_timers.values_num; i++) { zbx_trigger_timer_t *timer = (zbx_trigger_timer_t *)persistent_timers.values[i]; - zbx_db_insert_add_values(&db_insert, timer->objectid, timer->type, timer->eval_ts.sec, - timer->eval_ts.ns); + zbx_db_insert_add_values(&db_insert, __UINT64_C(0), timer->objectid, timer->type, + timer->eval_ts.sec, timer->eval_ts.ns); } zbx_dc_free_timers(&persistent_timers); + zbx_db_insert_autoincrement(&db_insert, "trigger_queueid"); zbx_db_insert_execute(&db_insert); zbx_db_insert_clean(&db_insert); } |