1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "checks_db.h"
21
22 #include "zbxjson.h"
23 #include "log.h"
24
25 #ifdef HAVE_UNIXODBC
26
27 #include "zbxodbc.h"
28
get_result_columns(ZBX_ODBC_DBH * dbh,char ** buffer)29 static int get_result_columns(ZBX_ODBC_DBH *dbh, char **buffer)
30 {
31 int ret = SUCCEED, i, j;
32 char str[MAX_STRING_LEN];
33 SQLRETURN rc;
34 SQLSMALLINT len;
35
36 for (i = 0; i < dbh->col_num; i++)
37 {
38 rc = SQLColAttribute(dbh->hstmt, i + 1, SQL_DESC_LABEL, str, sizeof(str), &len, NULL);
39
40 if (SQL_SUCCESS != rc || sizeof(str) <= (size_t)len || '\0' == *str)
41 {
42 for (j = 0; j < i; j++)
43 zbx_free(buffer[j]);
44
45 ret = FAIL;
46 break;
47 }
48
49 buffer[i] = zbx_strdup(NULL, str);
50 }
51
52 return ret;
53 }
54
db_odbc_discovery(DC_ITEM * item,AGENT_REQUEST * request,AGENT_RESULT * result)55 static int db_odbc_discovery(DC_ITEM *item, AGENT_REQUEST *request, AGENT_RESULT *result)
56 {
57 const char *__function_name = "db_odbc_discovery";
58
59 int ret = NOTSUPPORTED, i, j;
60 ZBX_ODBC_DBH dbh;
61 ZBX_ODBC_ROW row;
62 char **columns, *p, macro[MAX_STRING_LEN];
63 struct zbx_json json;
64
65 zabbix_log(LOG_LEVEL_DEBUG, "In %s() query:'%s'", __function_name, item->params);
66
67 if (2 != request->nparam)
68 {
69 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid number of parameters."));
70 goto out;
71 }
72
73 if (SUCCEED != odbc_DBconnect(&dbh, request->params[1], item->username, item->password, CONFIG_TIMEOUT))
74 {
75 SET_MSG_RESULT(result, zbx_strdup(NULL, get_last_odbc_strerror()));
76 goto out;
77 }
78
79 if (NULL != odbc_DBselect(&dbh, item->params))
80 {
81 columns = zbx_malloc(NULL, sizeof(char *) * dbh.col_num);
82
83 if (SUCCEED == get_result_columns(&dbh, columns))
84 {
85 for (i = 0; i < dbh.col_num; i++)
86 zabbix_log(LOG_LEVEL_DEBUG, "%s() column[%d]:'%s'", __function_name, i + 1, columns[i]);
87
88 for (i = 0; i < dbh.col_num; i++)
89 {
90 for (p = columns[i]; '\0' != *p; p++)
91 {
92 if (0 != isalpha((unsigned char)*p))
93 *p = toupper((unsigned char)*p);
94
95 if (SUCCEED != is_macro_char(*p))
96 {
97 SET_MSG_RESULT(result, zbx_dsprintf(NULL,
98 "Cannot convert column #%d name to macro.", i + 1));
99 goto clean;
100 }
101 }
102
103 for (j = 0; j < i; j++)
104 {
105 if (0 == strcmp(columns[i], columns[j]))
106 {
107 SET_MSG_RESULT(result, zbx_dsprintf(NULL,
108 "Duplicate macro name: {#%s}.", columns[i]));
109 goto clean;
110 }
111 }
112 }
113
114 zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
115 zbx_json_addarray(&json, ZBX_PROTO_TAG_DATA);
116
117 while (NULL != (row = odbc_DBfetch(&dbh)))
118 {
119 zbx_json_addobject(&json, NULL);
120
121 for (i = 0; i < dbh.col_num; i++)
122 {
123 zbx_snprintf(macro, MAX_STRING_LEN, "{#%s}", columns[i]);
124 zbx_json_addstring(&json, macro, row[i], ZBX_JSON_TYPE_STRING);
125 }
126
127 zbx_json_close(&json);
128 }
129
130 zbx_json_close(&json);
131
132 SET_STR_RESULT(result, zbx_strdup(NULL, json.buffer));
133
134 zbx_json_free(&json);
135
136 ret = SUCCEED;
137 clean:
138 for (i = 0; i < dbh.col_num; i++)
139 zbx_free(columns[i]);
140 }
141 else
142 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain column names."));
143
144 zbx_free(columns);
145 }
146 else
147 SET_MSG_RESULT(result, zbx_strdup(NULL, get_last_odbc_strerror()));
148
149 odbc_DBclose(&dbh);
150 out:
151 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
152
153 return ret;
154 }
155
db_odbc_select(DC_ITEM * item,AGENT_REQUEST * request,AGENT_RESULT * result)156 static int db_odbc_select(DC_ITEM *item, AGENT_REQUEST *request, AGENT_RESULT *result)
157 {
158 const char *__function_name = "db_odbc_select";
159
160 int ret = NOTSUPPORTED;
161 ZBX_ODBC_DBH dbh;
162 ZBX_ODBC_ROW row;
163
164 zabbix_log(LOG_LEVEL_DEBUG, "In %s() query:'%s'", __function_name, item->params);
165
166 if (2 != request->nparam)
167 {
168 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid number of parameters."));
169 goto out;
170 }
171
172 if (SUCCEED != odbc_DBconnect(&dbh, request->params[1], item->username, item->password, CONFIG_TIMEOUT))
173 {
174 SET_MSG_RESULT(result, zbx_strdup(NULL, get_last_odbc_strerror()));
175 goto out;
176 }
177
178 if (NULL != odbc_DBselect(&dbh, item->params))
179 {
180 if (NULL != (row = odbc_DBfetch(&dbh)))
181 {
182 if (NULL == row[0])
183 {
184 SET_MSG_RESULT(result, zbx_strdup(NULL, "SQL query returned NULL value."));
185 }
186 else if (SUCCEED == set_result_type(result, item->value_type, item->data_type, row[0]))
187 {
188 ret = SUCCEED;
189 }
190 }
191 else
192 {
193 const char *last_error = get_last_odbc_strerror();
194
195 if ('\0' != *last_error)
196 SET_MSG_RESULT(result, zbx_strdup(NULL, last_error));
197 else
198 SET_MSG_RESULT(result, zbx_strdup(NULL, "SQL query returned empty result."));
199 }
200 }
201 else
202 SET_MSG_RESULT(result, zbx_strdup(NULL, get_last_odbc_strerror()));
203
204 odbc_DBclose(&dbh);
205 out:
206 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
207
208 return ret;
209 }
210
211 /******************************************************************************
212 * *
213 * Function: get_value_db *
214 * *
215 * Purpose: retrieve data from database *
216 * *
217 * Parameters: item - item we are interested in *
218 * *
219 * Return value: SUCCEED - data successfully retrieved and stored in result *
220 * NOTSUPPORTED - requested item is not supported *
221 * *
222 * Author: Eugene Grigorjev *
223 * *
224 ******************************************************************************/
get_value_db(DC_ITEM * item,AGENT_RESULT * result)225 int get_value_db(DC_ITEM *item, AGENT_RESULT *result)
226 {
227 const char *__function_name = "get_value_db";
228
229 AGENT_REQUEST request;
230 int ret = NOTSUPPORTED;
231
232 zabbix_log(LOG_LEVEL_DEBUG, "In %s() key_orig:'%s'", __function_name, item->key_orig);
233
234 init_request(&request);
235
236 if (SUCCEED == parse_item_key(item->key, &request))
237 {
238 if (0 == strcmp(request.key, "db.odbc.select"))
239 ret = db_odbc_select(item, &request, result);
240 else if (0 == strcmp(request.key, "db.odbc.discovery"))
241 ret = db_odbc_discovery(item, &request, result);
242 else
243 SET_MSG_RESULT(result, zbx_strdup(NULL, "Unsupported item key for this item type."));
244 }
245 else
246 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid item parameter format."));
247
248 free_request(&request);
249
250 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
251
252 return ret;
253 }
254
255 #endif /* HAVE_UNIXODBC */
256