Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexander Shubin <aleksandrs.subins@zabbix.com>2021-05-10 17:49:31 +0300
committerAlexander Shubin <aleksandrs.subins@zabbix.com>2021-05-10 17:49:31 +0300
commit6884c1c7a2e9debd41f149f168b87250a249c0c6 (patch)
tree4dafc24a5ee5c70d3dc808eede06d8bf09768c43 /src
parent1ca32e7b027871a26432c1b9d2a5883740bd6231 (diff)
parentafed3e3c3669bec757c1b5eb92968f87ea1c9278 (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.go3
-rw-r--r--src/libs/zbxcommon/str.c15
-rw-r--r--src/libs/zbxdbcache/dbcache.c2
-rw-r--r--src/libs/zbxdbcache/dbconfig.c14
-rw-r--r--src/libs/zbxdbhigh/db.c3
-rw-r--r--src/libs/zbxdbhigh/trigger.c4
-rw-r--r--src/libs/zbxdbupgrade/dbupgrade_5030.c303
-rw-r--r--src/libs/zbxeval/Makefile.am4
-rw-r--r--src/libs/zbxeval/calc.c494
-rw-r--r--src/libs/zbxeval/execute.c1408
-rw-r--r--src/libs/zbxeval/misc.c4
-rw-r--r--src/libs/zbxeval/parse.c2
-rw-r--r--src/libs/zbxserver/evalfunc.c231
-rw-r--r--src/libs/zbxserver/evalfunc2.c442
-rw-r--r--src/libs/zbxserver/expression_eval.c9
-rw-r--r--src/zabbix_server/dbsyncer/dbsyncer.c7
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, &params, &params_alloc, &params_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(&regexps);
+
+ pattern = valuemap->value;
+
+ match = regexp_match_ex(&regexps, value, pattern, ZBX_CASE_SENSITIVE);
+
+ zbx_regexp_clean_expressions(&regexps);
+ zbx_vector_ptr_destroy(&regexps);
+
+ 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);
}