/* ** Zabbix ** Copyright (C) 2001-2023 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 "dbupgrade_macros.h" #include "dbupgrade.h" #include "zbxdbhigh.h" #include "zbxnum.h" /* Function argument descriptors. */ /* Used in varargs list to describe following parameter mapping to old position. */ /* Terminated with ZBX_DBPATCH_ARG_NONE. */ /* For example: */ /* ..., ZBX_DBPATCH_ARG_NUM, 1, ZBX_DBPATCH_ARG_STR, 0, ZBX_DBPATCH_ARG_NONE) */ /* meaning first numeric parameter copied from second parameter */ /* second string parameter copied from first parameter */ typedef enum { ZBX_DBPATCH_ARG_NONE, /* terminating descriptor, must be put at the end of the list */ ZBX_DBPATCH_ARG_HIST, /* history period followed by sec/num (int) and timeshift (int) indexes */ ZBX_DBPATCH_ARG_TIME, /* time value followed by argument index (int) */ ZBX_DBPATCH_ARG_NUM, /* number value followed by argument index (int) */ ZBX_DBPATCH_ARG_STR, /* string value followed by argument index (int) */ ZBX_DBPATCH_ARG_TREND, /* trend period, followed by period (int) and timeshift (int) indexes */ ZBX_DBPATCH_ARG_CONST_STR, /* constant,fffffff followed by string (char *) value */ } zbx_dbpatch_arg_t; ZBX_VECTOR_IMPL(strloc, zbx_strloc_t) /****************************************************************************** * * * Purpose: rename macros in the string * * * * Parameters: in - [IN] the input string * * oldmacro - [IN] the macro to rename * * newmacro - [IN] the new macro name * * out - [IN/OUT] the string with renamed macros * * out_alloc - [IN/OUT] the output buffer size * * * * Return value: SUCCEED - macros were found and renamed * * FAIL - no target macros were found * * * * Comments: If the oldmacro is found in input string then all occurrences of * * it are replaced with the new macro in the output string. * * Otherwise the output string is not changed. * * * ******************************************************************************/ static int str_rename_macro(const char *in, const char *oldmacro, const char *newmacro, char **out, size_t *out_alloc) { zbx_token_t token; int pos = 0, ret = FAIL; size_t out_offset = 0, newmacro_len; newmacro_len = strlen(newmacro); zbx_strcpy_alloc(out, out_alloc, &out_offset, in); out_offset++; for (; SUCCEED == zbx_token_find(*out, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++) { switch (token.type) { case ZBX_TOKEN_MACRO: pos = token.loc.r; if (0 == strncmp(*out + token.loc.l, oldmacro, token.loc.r - token.loc.l + 1)) { pos += zbx_replace_mem_dyn(out, out_alloc, &out_offset, token.loc.l, token.loc.r - token.loc.l + 1, newmacro, newmacro_len); ret = SUCCEED; } break; case ZBX_TOKEN_USER_MACRO: case ZBX_TOKEN_SIMPLE_MACRO: pos = token.loc.r; break; } } return ret; } /****************************************************************************** * * * Purpose: rename macro in the specified database fields * * * * Parameters: result - [IN] database query with fields to replace. First * * field is table id field, following with * * the target fields listed in fields parameter * * table - [IN] the target table name * * pkey - [IN] the primary key field name * * fields - [IN] the table fields to check for macros and * * rename if found * * fields_num - [IN] the number of fields to check * * oldmacro - [IN] the macro to rename * * newmacro - [IN] the new macro name * * * * Return value: SUCCEED - macros were renamed successfully * * FAIL - database error occurred * * * ******************************************************************************/ int db_rename_macro(DB_RESULT result, const char *table, const char *pkey, zbx_field_len_t *fields, int fields_num, const char *oldmacro, const char *newmacro) { DB_ROW row; char *sql = 0, *value = NULL, *value_esc; size_t sql_alloc = 4096, sql_offset = 0, field_alloc = 0, old_offset; int i, ret = SUCCEED; zbx_field_len_t *field; sql = zbx_malloc(NULL, sql_alloc); zbx_db_begin_multiple_update(&sql, &sql_alloc, &sql_offset); while (NULL != (row = zbx_db_fetch(result))) { old_offset = sql_offset; for (i = 0; i < fields_num; i++) { field = fields + i; if (SUCCEED == str_rename_macro(row[i + 1], oldmacro, newmacro, &value, &field_alloc)) { if (0 != field->max_len && zbx_strlen_utf8(value) > field->max_len) { zabbix_log(LOG_LEVEL_WARNING, "cannot rename macros in table \"%s\" row " "\"%s:%s\" field \"%s\": value is too long", table, pkey, row[0], field->field_name); continue; } value_esc = zbx_db_dyn_escape_string(value); if (old_offset == sql_offset) zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update %s set ", table); else zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ','); zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s='%s'", fields[i].field_name, value_esc); zbx_free(value_esc); } } if (old_offset != sql_offset) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where %s=%s;\n", pkey, row[0]); if (SUCCEED != (ret = zbx_db_execute_overflowed_sql(&sql, &sql_alloc, &sql_offset))) goto out; } } zbx_db_end_multiple_update(&sql, &sql_alloc, &sql_offset); if (16 < sql_offset && ZBX_DB_OK > zbx_db_execute("%s", sql)) ret = FAIL; out: zbx_free(value); zbx_free(sql); return ret; } void dbpatch_function_free(zbx_dbpatch_function_t *func) { zbx_free(func->name); zbx_free(func->parameter); zbx_free(func->arg0); zbx_free(func); } zbx_dbpatch_function_t *dbpatch_new_function(zbx_uint64_t functionid, zbx_uint64_t itemid, const char *name, const char *parameter, unsigned char flags) { zbx_dbpatch_function_t *func; func = (zbx_dbpatch_function_t *)zbx_malloc(NULL, sizeof(zbx_dbpatch_function_t)); func->functionid = functionid; func->itemid = itemid; func->name = (NULL != name ? zbx_strdup(NULL, name) : NULL); func->parameter = (NULL != parameter ? zbx_strdup(NULL, parameter) : NULL); func->flags = flags; func->arg0 = NULL; return func; } static void dbpatch_add_function(const zbx_dbpatch_function_t *template, zbx_uint64_t functionid, const char *name, const char *parameter, unsigned char flags, zbx_vector_ptr_t *functions) { zbx_dbpatch_function_t *func; func = dbpatch_new_function(functionid, template->itemid, name, parameter, flags); func->arg0 = (NULL != template->arg0 ? zbx_strdup(NULL, template->arg0) : NULL); zbx_vector_ptr_append(functions, func); } static void dbpatch_update_function(zbx_dbpatch_function_t *func, const char *name, const char *parameter, unsigned char flags) { if (0 != (flags & ZBX_DBPATCH_FUNCTION_UPDATE_NAME)) func->name = zbx_strdup(func->name, name); if (0 != (flags & ZBX_DBPATCH_FUNCTION_UPDATE_PARAM)) func->parameter = zbx_strdup(func->parameter, parameter); func->flags = flags; } int dbpatch_is_time_function(const char *name, size_t len) { const char *functions[] = {"date", "dayofmonth", "dayofweek", "now", "time", NULL}, **func; size_t func_len; for (func = functions; NULL != *func; func++) { func_len = strlen(*func); if (func_len == len && 0 == memcmp(*func, name, len)) return SUCCEED; } return FAIL; } static void dbpatch_update_func_abschange(zbx_dbpatch_function_t *function, char **replace) { dbpatch_update_function(function, "change", "", ZBX_DBPATCH_FUNCTION_UPDATE); *replace = zbx_dsprintf(NULL, "abs({" ZBX_FS_UI64 "})", function->functionid); } static void dbpatch_update_func_delta(zbx_dbpatch_function_t *function, const char *parameter, char **replace, zbx_vector_ptr_t *functions) { zbx_uint64_t functionid2; dbpatch_update_function(function, "max", parameter, ZBX_DBPATCH_FUNCTION_UPDATE); functionid2 = (NULL == function->arg0 ? zbx_db_get_maxid("functions") : (zbx_uint64_t)functions->values_num); dbpatch_add_function(function, functionid2, "min", parameter, ZBX_DBPATCH_FUNCTION_CREATE, functions); *replace = zbx_dsprintf(NULL, "({" ZBX_FS_UI64 "}-{" ZBX_FS_UI64 "})", function->functionid, functionid2); } static void dbpatch_update_func_diff(zbx_dbpatch_function_t *function, char **replace, zbx_vector_ptr_t *functions) { zbx_uint64_t functionid2; dbpatch_update_function(function, "last", "#1", ZBX_DBPATCH_FUNCTION_UPDATE); functionid2 = (NULL == function->arg0 ? zbx_db_get_maxid("functions") : (zbx_uint64_t)functions->values_num); dbpatch_add_function(function, functionid2, "last", "#2", ZBX_DBPATCH_FUNCTION_CREATE, functions); *replace = zbx_dsprintf(NULL, "({" ZBX_FS_UI64 "}<>{" ZBX_FS_UI64 "})", function->functionid, functionid2); } static void dbpatch_update_func_trenddelta(zbx_dbpatch_function_t *function, const char *parameter, char **replace, zbx_vector_ptr_t *functions) { zbx_uint64_t functionid2; dbpatch_update_function(function, "trendmax", parameter, ZBX_DBPATCH_FUNCTION_UPDATE); functionid2 = (NULL == function->arg0 ? zbx_db_get_maxid("functions") : (zbx_uint64_t)functions->values_num); dbpatch_add_function(function, functionid2, "trendmin", parameter, ZBX_DBPATCH_FUNCTION_CREATE, functions); *replace = zbx_dsprintf(NULL, "({" ZBX_FS_UI64 "}-{" ZBX_FS_UI64 "})", function->functionid, functionid2); } static void dbpatch_update_func_strlen(zbx_dbpatch_function_t *function, const char *parameter, char **replace) { dbpatch_update_function(function, "last", parameter, ZBX_DBPATCH_FUNCTION_UPDATE); *replace = zbx_dsprintf(NULL, "length({" ZBX_FS_UI64 "})", function->functionid); } void dbpatch_update_hist2common(zbx_dbpatch_function_t *function, int extended, char **expression) { char *str = NULL; size_t str_alloc = 0, str_offset = 0; if (ZBX_DBPATCH_FUNCTION_DELETE == function->flags) dbpatch_update_function(function, "last", "$", ZBX_DBPATCH_FUNCTION_UPDATE); if (0 == extended) zbx_chrcpy_alloc(&str, &str_alloc, &str_offset, '('); zbx_strcpy_alloc(&str, &str_alloc, &str_offset, *expression); if (0 == extended) zbx_chrcpy_alloc(&str, &str_alloc, &str_offset, ')'); zbx_snprintf_alloc(&str, &str_alloc, &str_offset, " or ({" ZBX_FS_UI64 "}<>{" ZBX_FS_UI64 "})", function->functionid, function->functionid); zbx_free(*expression); *expression = str; } static void dbpatch_update_func_bitand(zbx_dbpatch_function_t *function, const zbx_vector_strloc_t *params, char **replace) { char *parameter = NULL, *mask = NULL; int secnum = 0; if (2 <= params->values_num && '\0' != function->parameter[params->values[1].l]) { mask = zbx_substr_unquote(function->parameter, params->values[1].l, params->values[1].r); *replace = zbx_dsprintf(NULL, "bitand({" ZBX_FS_UI64 "},%s)", function->functionid, mask); zbx_free(mask); } else *replace = zbx_dsprintf(NULL, "bitand({" ZBX_FS_UI64 "})", function->functionid); if (0 < params->values_num) { char *param; param = zbx_substr_unquote(function->parameter, params->values[0].l, params->values[0].r); if ('#' != *param && '{' != *param) secnum = -1; zbx_free(param); } dbpatch_convert_params(¶meter, function->parameter, params, ZBX_DBPATCH_ARG_HIST, secnum, 2, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, "last", parameter, ZBX_DBPATCH_FUNCTION_UPDATE); zbx_free(parameter); } /****************************************************************************** * * * Purpose: quote and text to a buffer * * * * Parameters: str - [OUT] the output buffer * * str_alloc - [IN/OUT] an offset in the output buffer * * str_offset - [IN/OUT] the size of the output buffer * * source - [IN] the source text * * * * Return value: SUCCEED - the text is a composite constant * * FAIL - otherwise * * * ******************************************************************************/ void dbpatch_strcpy_alloc_quoted(char **str, size_t *str_alloc, size_t *str_offset, const char *source) { char raw[ZBX_DBPATCH_FUNCTION_PARAM_LEN * 5 + 1], quoted[sizeof(raw)]; zbx_strlcpy(raw, source, sizeof(raw)); zbx_escape_string(quoted, sizeof(quoted), raw, "\"\\"); zbx_chrcpy_alloc(str, str_alloc, str_offset, '"'); zbx_strcpy_alloc(str, str_alloc, str_offset, quoted); zbx_chrcpy_alloc(str, str_alloc, str_offset, '"'); } /****************************************************************************** * * * Purpose: check for composite (consisting of macro(s) + text) constant * * * * Parameters: str - [IN] the text to check * * * * Return value: SUCCEED - the text is a composite constant * * FAIL - otherwise * * * ******************************************************************************/ int dbpatch_is_composite_constant(const char *str) { zbx_token_t token; if (SUCCEED == zbx_token_find(str, 0, &token, ZBX_TOKEN_SEARCH_BASIC | ZBX_TOKEN_SEARCH_SIMPLE_MACRO)) { if (ZBX_TOKEN_USER_MACRO != token.type && ZBX_TOKEN_LLD_MACRO != token.type) return SUCCEED; if (0 != token.loc.l || strlen(str) - 1 != token.loc.r) return SUCCEED; } return FAIL; } /****************************************************************************** * * * Purpose: convert function parameters into new syntax * * * * Parameters: out - [OUT] the converted parameter string * * parameter - [IN] the original parameter string * * params - [IN] the parameter locations in original parameter * * string * * ... - list of parameter descriptors with parameter data * * (see zbx_dbpatch_arg_t enum for parameter list * * description) * * * ******************************************************************************/ void dbpatch_convert_params(char **out, const char *parameter, const zbx_vector_strloc_t *params, ...) { size_t out_alloc = 0, out_offset = 0; va_list args; int index, type, param_num = 0; const zbx_strloc_t *loc; const char *ptr; char *arg; va_start(args, params); while (ZBX_DBPATCH_ARG_NONE != (type = va_arg(args, int))) { if (0 != param_num++) zbx_chrcpy_alloc(out, &out_alloc, &out_offset, ','); switch (type) { case ZBX_DBPATCH_ARG_HIST: if (-1 != (index = va_arg(args, int)) && index < params->values_num) { loc = ¶ms->values[index]; arg = zbx_substr_unquote(parameter, loc->l, loc->r); if ('\0' != *arg) { zbx_strcpy_alloc(out, &out_alloc, &out_offset, arg); if ('#' != *arg && 0 != isdigit(arg[strlen(arg) - 1])) zbx_chrcpy_alloc(out, &out_alloc, &out_offset, 's'); } zbx_free(arg); } if (-1 != (index = va_arg(args, int)) && index < params->values_num) { loc = ¶ms->values[index]; arg = zbx_substr_unquote(parameter, loc->l, loc->r); if ('\0' != *arg) { if (0 == out_offset) zbx_strcpy_alloc(out, &out_alloc, &out_offset, "#1"); zbx_strcpy_alloc(out, &out_alloc, &out_offset, ":now-"); zbx_strcpy_alloc(out, &out_alloc, &out_offset, arg); if (0 != isdigit(arg[strlen(arg) - 1])) zbx_chrcpy_alloc(out, &out_alloc, &out_offset, 's'); } zbx_free(arg); } break; case ZBX_DBPATCH_ARG_TIME: if (params->values_num > (index = va_arg(args, int))) { char *str; loc = ¶ms->values[index]; str = zbx_substr_unquote(parameter, loc->l, loc->r); if ('\0' != *str) { if (SUCCEED == dbpatch_is_composite_constant(str)) dbpatch_strcpy_alloc_quoted(out, &out_alloc, &out_offset, str); else zbx_strcpy_alloc(out, &out_alloc, &out_offset, str); if (0 != isdigit((*out)[out_offset - 1])) zbx_chrcpy_alloc(out, &out_alloc, &out_offset, 's'); } zbx_free(str); } break; case ZBX_DBPATCH_ARG_NUM: if (params->values_num > (index = va_arg(args, int))) { char *str; loc = ¶ms->values[index]; str = zbx_substr_unquote(parameter, loc->l, loc->r); if (SUCCEED == dbpatch_is_composite_constant(str)) dbpatch_strcpy_alloc_quoted(out, &out_alloc, &out_offset, str); else zbx_strcpy_alloc(out, &out_alloc, &out_offset, str); zbx_free(str); } break; case ZBX_DBPATCH_ARG_STR: if (params->values_num > (index = va_arg(args, int))) { char *str; loc = ¶ms->values[index]; str = zbx_substr_unquote(parameter, loc->l, loc->r); dbpatch_strcpy_alloc_quoted(out, &out_alloc, &out_offset, str); zbx_free(str); } break; case ZBX_DBPATCH_ARG_TREND: if (params->values_num > (index = va_arg(args, int))) { char *str; loc = ¶ms->values[index]; str = zbx_substr_unquote(parameter, loc->l, loc->r); zbx_strcpy_alloc(out, &out_alloc, &out_offset, str); zbx_free(str); } if (params->values_num > (index = va_arg(args, int))) { char *str; loc = ¶ms->values[index]; str = zbx_substr_unquote(parameter, loc->l, loc->r); zbx_chrcpy_alloc(out, &out_alloc, &out_offset, ':'); zbx_strcpy_alloc(out, &out_alloc, &out_offset, str); zbx_free(str); } break; case ZBX_DBPATCH_ARG_CONST_STR: if (NULL != (ptr = va_arg(args, char *))) { char quoted[MAX_STRING_LEN]; zbx_escape_string(quoted, sizeof(quoted), ptr, "\"\\"); zbx_chrcpy_alloc(out, &out_alloc, &out_offset, '"'); zbx_strcpy_alloc(out, &out_alloc, &out_offset, quoted); zbx_chrcpy_alloc(out, &out_alloc, &out_offset, '"'); } break; } } va_end(args); if (0 != out_offset) { /* trim trailing empty parameters */ while (0 < out_offset && ',' == (*out)[out_offset - 1]) (*out)[--out_offset] = '\0'; } else *out = zbx_strdup(*out, ""); } /****************************************************************************** * * * Purpose: parse function parameter string into parameter location vector * * * ******************************************************************************/ static void dbpatch_parse_function_params(const char *parameter, zbx_vector_strloc_t *params) { const char *ptr; size_t len, pos, sep = 0, eol; zbx_strloc_t loc; eol = strlen(parameter); for (ptr = parameter; ptr < parameter + eol; ptr += sep + 1) { zbx_function_param_parse(ptr, &pos, &len, &sep); if (0 < len) { loc.l = ptr - parameter + pos; loc.r = loc.l + len - 1; } else { loc.l = ptr - parameter + eol - (ptr - parameter); loc.r = loc.l; } zbx_vector_strloc_append_ptr(params, &loc); } while (0 < params->values_num && '\0' == parameter[params->values[params->values_num - 1].l]) --params->values_num; } /****************************************************************************** * * * Purpose: convert function to new parameter syntax/order * * * * Parameters: function - [IN/OUT] the function to convert * * replace - [OUT] the replacement for {functionid} in the * * expression * * functions - [IN/OUT] the functions * * * * Comments: The function conversion can result in another function being * * added. * * * ******************************************************************************/ void dbpatch_convert_function(zbx_dbpatch_function_t *function, char **replace, zbx_vector_ptr_t *functions) { zbx_vector_strloc_t params; char *parameter = NULL; zbx_vector_strloc_create(¶ms); dbpatch_parse_function_params(function->parameter, ¶ms); if (0 == strcmp(function->name, "abschange")) { dbpatch_update_func_abschange(function, replace); } else if (0 == strcmp(function->name, "change")) { dbpatch_update_function(function, NULL, "", ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); } else if (0 == strcmp(function->name, "avg") || 0 == strcmp(function->name, "max") || 0 == strcmp(function->name, "min") || 0 == strcmp(function->name, "sum")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, 0, 1, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, NULL, parameter, ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); } else if (0 == strcmp(function->name, "delta")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, 0, 1, ZBX_DBPATCH_ARG_NONE); dbpatch_update_func_delta(function, parameter, replace, functions); } else if (0 == strcmp(function->name, "diff")) { dbpatch_update_func_diff(function, replace, functions); } else if (0 == strcmp(function->name, "fuzzytime")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_TIME, 0, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, NULL, parameter, ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); } else if (0 == strcmp(function->name, "nodata")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_TIME, 0, ZBX_DBPATCH_ARG_STR, 1, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, NULL, parameter, ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); } else if (0 == strcmp(function->name, "percentile")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, 0, 1, ZBX_DBPATCH_ARG_NUM, 2, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, NULL, parameter, ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); } else if (0 == strcmp(function->name, "trendavg") || 0 == strcmp(function->name, "trendmin") || 0 == strcmp(function->name, "trendmax") || 0 == strcmp(function->name, "trendsum") || 0 == strcmp(function->name, "trendcount")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_TREND, 0, 1, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, NULL, parameter, ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); } else if (0 == strcmp(function->name, "trenddelta")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_TREND, 0, 1, ZBX_DBPATCH_ARG_NONE); dbpatch_update_func_trenddelta(function, parameter, replace, functions); } else if (0 == strcmp(function->name, "band")) { dbpatch_update_func_bitand(function, ¶ms, replace); } else if (0 == strcmp(function->name, "forecast")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, 0, 1, ZBX_DBPATCH_ARG_TIME, 2, ZBX_DBPATCH_ARG_STR, 3, ZBX_DBPATCH_ARG_STR, 4, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, NULL, parameter, ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); } else if (0 == strcmp(function->name, "timeleft")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, 0, 1, ZBX_DBPATCH_ARG_NUM, 2, ZBX_DBPATCH_ARG_STR, 3, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, NULL, parameter, ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); } else if (0 == strcmp(function->name, "count")) { char *op = NULL; if (2 <= params.values_num) { if (3 <= params.values_num && '\0' != function->parameter[params.values[2].l]) { op = zbx_substr_unquote(function->parameter, params.values[2].l, params.values[2].r); if (0 == strcmp(op, "band")) op = zbx_strdup(op, "bitand"); else if ('\0' == *op && '"' != function->parameter[params.values[2].l]) zbx_free(op); } } dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, 0, 3, ZBX_DBPATCH_ARG_CONST_STR, op, ZBX_DBPATCH_ARG_STR, 1, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, NULL, parameter, ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); zbx_free(op); } else if (0 == strcmp(function->name, "iregexp") || 0 == strcmp(function->name, "regexp")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, 1, -1, ZBX_DBPATCH_ARG_CONST_STR, function->name, ZBX_DBPATCH_ARG_STR, 0, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, "find", parameter, ZBX_DBPATCH_FUNCTION_UPDATE); } else if (0 == strcmp(function->name, "str")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, 1, -1, ZBX_DBPATCH_ARG_CONST_STR, "like", ZBX_DBPATCH_ARG_STR, 0, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, "find", parameter, ZBX_DBPATCH_FUNCTION_UPDATE); } else if (0 == strcmp(function->name, "last")) { int secnum = 0; if (0 < params.values_num) { char *param; param = zbx_substr_unquote(function->parameter, params.values[0].l, params.values[0].r); if ('#' != *param && '{' != *param) secnum = -1; zbx_free(param); } dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, secnum, 1, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, NULL, parameter, ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); } else if (0 == strcmp(function->name, "prev")) { dbpatch_update_function(function, "last", "#2", ZBX_DBPATCH_FUNCTION_UPDATE); } else if (0 == strcmp(function->name, "strlen")) { int secnum = 0; if (0 < params.values_num) { char *param; param = zbx_substr_unquote(function->parameter, params.values[0].l, params.values[0].r); if ('#' != *param && '{' != *param) secnum = -1; zbx_free(param); } dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, secnum, 1, ZBX_DBPATCH_ARG_NONE); dbpatch_update_func_strlen(function, parameter, replace); } else if (0 == strcmp(function->name, "logeventid") || 0 == strcmp(function->name, "logsource")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, -1, -1, ZBX_DBPATCH_ARG_STR, 0, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, NULL, parameter, ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); } else if (0 == strcmp(function->name, "logseverity")) { dbpatch_convert_params(¶meter, function->parameter, ¶ms, ZBX_DBPATCH_ARG_HIST, -1, -1, ZBX_DBPATCH_ARG_NONE); dbpatch_update_function(function, NULL, "", ZBX_DBPATCH_FUNCTION_UPDATE_PARAM); } zbx_free(parameter); zbx_vector_strloc_destroy(¶ms); } /****************************************************************************** * * * Purpose: replace functionids {<index in functions vector>} in expression * * with their string format * * * * Parameters: expression - [IN/OUT] the expression * * functions - [IN] the functions * * * ******************************************************************************/ static void dbpatch_replace_functionids(char **expression, const zbx_vector_ptr_t *functions) { zbx_uint64_t index; int pos = 0, last_pos = 0; zbx_token_t token; char *out = NULL; size_t out_alloc = 0, out_offset = 0; for (; SUCCEED == zbx_token_find(*expression, pos, &token, ZBX_TOKEN_SEARCH_FUNCTIONID | ZBX_TOKEN_SEARCH_SIMPLE_MACRO); pos++) { switch (token.type) { case ZBX_TOKEN_OBJECTID: if (SUCCEED == zbx_is_uint64_n(*expression + token.loc.l + 1, token.loc.r - token.loc.l - 1, &index) && (int)index < functions->values_num) { zbx_dbpatch_function_t *func = functions->values[index]; zbx_strncpy_alloc(&out, &out_alloc, &out_offset, *expression + last_pos, token.loc.l - last_pos); zbx_snprintf_alloc(&out, &out_alloc, &out_offset, "%s(%s", func->name, func->arg0); if ('\0' != *func->parameter) { zbx_chrcpy_alloc(&out, &out_alloc, &out_offset, ','); zbx_strcpy_alloc(&out, &out_alloc, &out_offset, func->parameter); } zbx_chrcpy_alloc(&out, &out_alloc, &out_offset, ')'); last_pos = token.loc.r + 1; } pos = token.loc.r; break; case ZBX_TOKEN_MACRO: case ZBX_TOKEN_USER_MACRO: case ZBX_TOKEN_LLD_MACRO: pos = token.loc.r; break; } } if (0 != out_alloc) { zbx_strcpy_alloc(&out, &out_alloc, &out_offset, *expression + last_pos); zbx_free(*expression); *expression = out; } } /****************************************************************************** * * * Purpose: convert simple macro {host.key:func(params)} to the new syntax * * func(/host/key,params) * * * * Parameters: expression - [IN] the expression with simple macro * * data - [IN] the simple macro token data * * more - [IN] also replace {HOSTNAME*} and {HOST.HOST1} * * function - [OUT] the simple macro replacement function * * * ******************************************************************************/ void dbpatch_convert_simple_macro(const char *expression, const zbx_token_simple_macro_t *data, int more, char **function) { #define HOSTHOST_STR "{HOST.HOST" #define HOSTNAME_STR "{HOSTNAME" #define HOSTHOST_IDX_POS ZBX_CONST_STRLEN(HOSTHOST_STR) #define HOSTNAME_IDX_POS ZBX_CONST_STRLEN(HOSTNAME_STR) zbx_dbpatch_function_t *func; zbx_vector_ptr_t functions; char *name, *host, *key; int pos; name = zbx_substr(expression, data->func.l, data->func_param.l - 1); if (SUCCEED == dbpatch_is_time_function(name, strlen(name))) { *function = zbx_dsprintf(NULL, "%s()", name); zbx_free(name); return; } zbx_vector_ptr_create(&functions); func = (zbx_dbpatch_function_t *)zbx_malloc(NULL, sizeof(zbx_dbpatch_function_t)); func->functionid = 0; func->itemid = 0; func->flags = 0; func->name = name; if (data->func_param.l + 1 == data->func_param.r) func->parameter = zbx_strdup(NULL, ""); else func->parameter = zbx_substr(expression, data->func_param.l + 1, data->func_param.r - 1); host = zbx_substr(expression, data->host.l, data->host.r); key = zbx_substr(expression, data->key.l, data->key.r); if (0 == strncmp(host, HOSTHOST_STR, HOSTHOST_IDX_POS)) pos = HOSTHOST_IDX_POS; else if (0 != more && 0 == strncmp(host, HOSTNAME_STR, HOSTNAME_IDX_POS)) pos = HOSTNAME_IDX_POS; else pos = 0; if ((0 != pos && (('}' == host[pos] && '\0' == host[pos + 1]) || (0 != more && 0 == strcmp("1}", host + pos))))) { func->arg0 = zbx_dsprintf(NULL, "//%s", key); } else if (HOSTNAME_IDX_POS == pos && isdigit(host[pos]) && '0' != host[pos] && '}' == host[pos + 1] && '\0' == host[pos + 2]) { func->arg0 = zbx_dsprintf(NULL, "/{HOST.HOST%c}/%s", host[pos], key); } else func->arg0 = zbx_dsprintf(NULL, "/%s/%s", host, key); zbx_vector_ptr_append(&functions, func); dbpatch_convert_function(func, function, &functions); if (NULL == *function) *function = zbx_strdup(NULL, "{0}"); dbpatch_replace_functionids(function, &functions); zbx_free(key); zbx_free(host); zbx_vector_ptr_clear_ext(&functions, (zbx_clean_func_t)dbpatch_function_free); zbx_vector_ptr_destroy(&functions); #undef HOSTHOST_IDX_POS #undef HOSTNAME_IDX_POS #undef HOSTHOST_STR #undef HOSTNAME_STR }