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 "common.h"
21 
22 #include "zbxdb.h"
23 
24 #if defined(HAVE_MYSQL)
25 #	include "mysql.h"
26 #	include "errmsg.h"
27 #	include "mysqld_error.h"
28 #elif defined(HAVE_ORACLE)
29 #	include "oci.h"
30 #elif defined(HAVE_POSTGRESQL)
31 #	include <libpq-fe.h>
32 #elif defined(HAVE_SQLITE3)
33 #	include <sqlite3.h>
34 #endif
35 
36 #include "dbschema.h"
37 #include "log.h"
38 #if defined(HAVE_SQLITE3)
39 #	include "mutexs.h"
40 #endif
41 
42 struct zbx_db_result
43 {
44 #if defined(HAVE_MYSQL)
45 	MYSQL_RES	*result;
46 #elif defined(HAVE_ORACLE)
47 	OCIStmt		*stmthp;	/* the statement handle for select operations */
48 	int		ncolumn;
49 	DB_ROW		values;
50 	ub4		*values_alloc;
51 	OCILobLocator	**clobs;
52 #elif defined(HAVE_POSTGRESQL)
53 	PGresult	*pg_result;
54 	int		row_num;
55 	int		fld_num;
56 	int		cursor;
57 	DB_ROW		values;
58 #elif defined(HAVE_SQLITE3)
59 	int		curow;
60 	char		**data;
61 	int		nrow;
62 	int		ncolumn;
63 	DB_ROW		values;
64 #endif
65 };
66 
67 static int	txn_level = 0;	/* transaction level, nested transactions are not supported */
68 static int	txn_error = ZBX_DB_OK;	/* failed transaction */
69 static int	txn_end_error = ZBX_DB_OK;	/* transaction result */
70 
71 static char	*last_db_strerror = NULL;	/* last database error message */
72 
73 extern int	CONFIG_LOG_SLOW_QUERIES;
74 
75 static int	db_auto_increment;
76 
77 #if defined(HAVE_MYSQL)
78 static MYSQL			*conn = NULL;
79 static zbx_uint32_t		ZBX_MYSQL_SVERSION = ZBX_DBVERSION_UNDEFINED;
80 static int			ZBX_MARIADB_SFORK = OFF;
81 #elif defined(HAVE_ORACLE)
82 #include "zbxalgo.h"
83 
84 typedef struct
85 {
86 	OCIEnv			*envhp;
87 	OCIError		*errhp;
88 	OCISvcCtx		*svchp;
89 	OCIServer		*srvhp;
90 	OCIStmt			*stmthp;	/* the statement handle for execute operations */
91 	zbx_vector_ptr_t	db_results;
92 }
93 zbx_oracle_db_handle_t;
94 
95 static zbx_uint32_t		ZBX_ORACLE_SVERSION = ZBX_DBVERSION_UNDEFINED;
96 
97 static zbx_oracle_db_handle_t	oracle;
98 
99 static ub4	OCI_DBserver_status(void);
100 
101 #elif defined(HAVE_POSTGRESQL)
102 static PGconn			*conn = NULL;
103 static unsigned int		ZBX_PG_BYTEAOID = 0;
104 static int			ZBX_TSDB_VERSION = -1;
105 static zbx_uint32_t		ZBX_PG_SVERSION = ZBX_DBVERSION_UNDEFINED;
106 char				ZBX_PG_ESCAPE_BACKSLASH = 1;
107 #elif defined(HAVE_SQLITE3)
108 static sqlite3			*conn = NULL;
109 static zbx_mutex_t		sqlite_access = ZBX_MUTEX_NULL;
110 #endif
111 
112 #if defined(HAVE_ORACLE)
113 static void	OCI_DBclean_result(DB_RESULT result);
114 #endif
115 
zbx_db_errlog(zbx_err_codes_t zbx_errno,int db_errno,const char * db_error,const char * context)116 static void	zbx_db_errlog(zbx_err_codes_t zbx_errno, int db_errno, const char *db_error, const char *context)
117 {
118 	char	*s;
119 
120 	if (NULL != db_error)
121 		last_db_strerror = zbx_strdup(last_db_strerror, db_error);
122 	else
123 		last_db_strerror = zbx_strdup(last_db_strerror, "");
124 
125 	switch (zbx_errno)
126 	{
127 		case ERR_Z3001:
128 			s = zbx_dsprintf(NULL, "connection to database '%s' failed: [%d] %s", context, db_errno,
129 					last_db_strerror);
130 			break;
131 		case ERR_Z3002:
132 			s = zbx_dsprintf(NULL, "cannot create database '%s': [%d] %s", context, db_errno,
133 					last_db_strerror);
134 			break;
135 		case ERR_Z3003:
136 			s = zbx_strdup(NULL, "no connection to the database");
137 			break;
138 		case ERR_Z3004:
139 			s = zbx_dsprintf(NULL, "cannot close database: [%d] %s", db_errno, last_db_strerror);
140 			break;
141 		case ERR_Z3005:
142 			s = zbx_dsprintf(NULL, "query failed: [%d] %s [%s]", db_errno, last_db_strerror, context);
143 			break;
144 		case ERR_Z3006:
145 			s = zbx_dsprintf(NULL, "fetch failed: [%d] %s", db_errno, last_db_strerror);
146 			break;
147 		case ERR_Z3007:
148 			s = zbx_dsprintf(NULL, "query failed: [%d] %s", db_errno, last_db_strerror);
149 			break;
150 		default:
151 			s = zbx_strdup(NULL, "unknown error");
152 	}
153 
154 	zabbix_log(LOG_LEVEL_ERR, "[Z%04d] %s", (int)zbx_errno, s);
155 
156 	zbx_free(s);
157 }
158 
159 /******************************************************************************
160  *                                                                            *
161  * Function: zbx_db_last_strerr                                               *
162  *                                                                            *
163  * Purpose: get last error set by database                                    *
164  *                                                                            *
165  * Return value: last database error message                                  *
166  *                                                                            *
167  ******************************************************************************/
168 
zbx_db_last_strerr(void)169 const char	*zbx_db_last_strerr(void)
170 {
171 	return last_db_strerror;
172 }
173 
174 #if defined(HAVE_ORACLE)
zbx_oci_error(sword status,sb4 * err)175 static const char	*zbx_oci_error(sword status, sb4 *err)
176 {
177 	static char	errbuf[512];
178 	sb4		errcode, *perrcode;
179 
180 	perrcode = (NULL == err ? &errcode : err);
181 
182 	errbuf[0] = '\0';
183 	*perrcode = 0;
184 
185 	switch (status)
186 	{
187 		case OCI_SUCCESS_WITH_INFO:
188 			OCIErrorGet((dvoid *)oracle.errhp, (ub4)1, (text *)NULL, perrcode,
189 					(text *)errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);
190 			break;
191 		case OCI_NEED_DATA:
192 			zbx_snprintf(errbuf, sizeof(errbuf), "%s", "OCI_NEED_DATA");
193 			break;
194 		case OCI_NO_DATA:
195 			zbx_snprintf(errbuf, sizeof(errbuf), "%s", "OCI_NODATA");
196 			break;
197 		case OCI_ERROR:
198 			OCIErrorGet((dvoid *)oracle.errhp, (ub4)1, (text *)NULL, perrcode,
199 					(text *)errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);
200 			break;
201 		case OCI_INVALID_HANDLE:
202 			zbx_snprintf(errbuf, sizeof(errbuf), "%s", "OCI_INVALID_HANDLE");
203 			break;
204 		case OCI_STILL_EXECUTING:
205 			zbx_snprintf(errbuf, sizeof(errbuf), "%s", "OCI_STILL_EXECUTING");
206 			break;
207 		case OCI_CONTINUE:
208 			zbx_snprintf(errbuf, sizeof(errbuf), "%s", "OCI_CONTINUE");
209 			break;
210 	}
211 
212 	zbx_rtrim(errbuf, ZBX_WHITESPACE);
213 
214 	return errbuf;
215 }
216 
217 /******************************************************************************
218  *                                                                            *
219  * Function: OCI_handle_sql_error                                             *
220  *                                                                            *
221  * Purpose: handles Oracle prepare/bind/execute/select operation error        *
222  *                                                                            *
223  * Parameters: zerrcode   - [IN] the Zabbix errorcode for the failed database *
224  *                               operation                                    *
225  *             oci_error  - [IN] the return code from failed Oracle operation *
226  *             sql        - [IN] the failed sql statement (can be NULL)       *
227  *                                                                            *
228  * Return value: ZBX_DB_DOWN - database connection is down                    *
229  *               ZBX_DB_FAIL - otherwise                                      *
230  *                                                                            *
231  * Comments: This function logs the error description and checks the          *
232  *           database connection status.                                      *
233  *                                                                            *
234  ******************************************************************************/
OCI_handle_sql_error(int zerrcode,sword oci_error,const char * sql)235 static int	OCI_handle_sql_error(int zerrcode, sword oci_error, const char *sql)
236 {
237 	sb4	errcode;
238 	int	ret = ZBX_DB_DOWN;
239 
240 	zbx_db_errlog(zerrcode, oci_error, zbx_oci_error(oci_error, &errcode), sql);
241 
242 	/* after ORA-02396 (and consequent ORA-01012) errors the OCI_SERVER_NORMAL server status is still returned */
243 	switch (errcode)
244 	{
245 		case 1012:	/* ORA-01012: not logged on */
246 		case 2396:	/* ORA-02396: exceeded maximum idle time */
247 			goto out;
248 	}
249 
250 	if (OCI_SERVER_NORMAL == OCI_DBserver_status())
251 		ret = ZBX_DB_FAIL;
252 out:
253 	return ret;
254 }
255 
256 #endif	/* HAVE_ORACLE */
257 
258 #ifdef HAVE_POSTGRESQL
zbx_postgresql_error(char ** error,const PGresult * pg_result)259 static void	zbx_postgresql_error(char **error, const PGresult *pg_result)
260 {
261 	char	*result_error_msg;
262 	size_t	error_alloc = 0, error_offset = 0;
263 
264 	zbx_snprintf_alloc(error, &error_alloc, &error_offset, "%s", PQresStatus(PQresultStatus(pg_result)));
265 
266 	result_error_msg = PQresultErrorMessage(pg_result);
267 
268 	if ('\0' != *result_error_msg)
269 		zbx_snprintf_alloc(error, &error_alloc, &error_offset, ":%s", result_error_msg);
270 }
271 #endif /*HAVE_POSTGRESQL*/
272 
273 __zbx_attr_format_printf(1, 2)
zbx_db_execute(const char * fmt,...)274 static int	zbx_db_execute(const char *fmt, ...)
275 {
276 	va_list	args;
277 	int	ret;
278 
279 	va_start(args, fmt);
280 	ret = zbx_db_vexecute(fmt, args);
281 	va_end(args);
282 
283 	return ret;
284 }
285 
286 __zbx_attr_format_printf(1, 2)
zbx_db_select(const char * fmt,...)287 static DB_RESULT	zbx_db_select(const char *fmt, ...)
288 {
289 	va_list		args;
290 	DB_RESULT	result;
291 
292 	va_start(args, fmt);
293 	result = zbx_db_vselect(fmt, args);
294 	va_end(args);
295 
296 	return result;
297 }
298 
299 #if defined(HAVE_MYSQL)
is_recoverable_mysql_error(void)300 static int	is_recoverable_mysql_error(void)
301 {
302 	switch (mysql_errno(conn))
303 	{
304 		case CR_CONN_HOST_ERROR:
305 		case CR_SERVER_GONE_ERROR:
306 		case CR_CONNECTION_ERROR:
307 		case CR_SERVER_LOST:
308 		case CR_UNKNOWN_HOST:
309 		case CR_COMMANDS_OUT_OF_SYNC:
310 		case ER_SERVER_SHUTDOWN:
311 		case ER_ACCESS_DENIED_ERROR:		/* wrong user or password */
312 		case ER_ILLEGAL_GRANT_FOR_TABLE:	/* user without any privileges */
313 		case ER_TABLEACCESS_DENIED_ERROR:	/* user without some privilege */
314 		case ER_UNKNOWN_ERROR:
315 		case ER_UNKNOWN_COM_ERROR:
316 		case ER_LOCK_DEADLOCK:
317 		case ER_LOCK_WAIT_TIMEOUT:
318 #ifdef CR_SSL_CONNECTION_ERROR
319 		case CR_SSL_CONNECTION_ERROR:
320 #endif
321 #ifdef ER_CONNECTION_KILLED
322 		case ER_CONNECTION_KILLED:
323 #endif
324 			return SUCCEED;
325 	}
326 
327 	return FAIL;
328 }
329 #elif defined(HAVE_POSTGRESQL)
is_recoverable_postgresql_error(const PGconn * pg_conn,const PGresult * pg_result)330 static int	is_recoverable_postgresql_error(const PGconn *pg_conn, const PGresult *pg_result)
331 {
332 	if (CONNECTION_OK != PQstatus(pg_conn))
333 		return SUCCEED;
334 
335 	if (0 == zbx_strcmp_null(PQresultErrorField(pg_result, PG_DIAG_SQLSTATE), "40P01"))
336 		return SUCCEED;
337 
338 	return FAIL;
339 }
340 #endif
341 
342 /******************************************************************************
343  *                                                                            *
344  * Function: zbx_db_init_autoincrement_options                                *
345  *                                                                            *
346  * Purpose: specify the autoincrement options during db connect               *
347  *                                                                            *
348  ******************************************************************************/
zbx_db_init_autoincrement_options(void)349 void	zbx_db_init_autoincrement_options(void)
350 {
351 	db_auto_increment = 1;
352 }
353 
354 /******************************************************************************
355  *                                                                            *
356  * Function: zbx_db_connect                                                   *
357  *                                                                            *
358  * Purpose: connect to the database                                           *
359  *                                                                            *
360  * Return value: ZBX_DB_OK - successfully connected                           *
361  *               ZBX_DB_DOWN - database is down                               *
362  *               ZBX_DB_FAIL - failed to connect                              *
363  *                                                                            *
364  ******************************************************************************/
zbx_db_connect(char * host,char * user,char * password,char * dbname,char * dbschema,char * dbsocket,int port,char * tls_connect,char * cert,char * key,char * ca,char * cipher,char * cipher_13)365 int	zbx_db_connect(char *host, char *user, char *password, char *dbname, char *dbschema, char *dbsocket, int port,
366 			char *tls_connect, char *cert, char *key, char *ca, char *cipher, char *cipher_13)
367 {
368 	int		ret = ZBX_DB_OK, last_txn_error, last_txn_level;
369 #if defined(HAVE_MYSQL)
370 #if LIBMYSQL_VERSION_ID >= 80000	/* my_bool type is removed in MySQL 8.0 */
371 	bool		mysql_reconnect = 1;
372 #else
373 	my_bool		mysql_reconnect = 1;
374 #endif
375 #elif defined(HAVE_ORACLE)
376 	char		*connect = NULL;
377 	sword		err = OCI_SUCCESS;
378 	static ub2	csid = 0;
379 #elif defined(HAVE_POSTGRESQL)
380 #	define ZBX_DB_MAX_PARAMS	9
381 
382 	int		rc;
383 	char		*cport = NULL;
384 	DB_RESULT	result;
385 	DB_ROW		row;
386 	const char	*keywords[ZBX_DB_MAX_PARAMS + 1];
387 	const char	*values[ZBX_DB_MAX_PARAMS + 1];
388 	unsigned int	i = 0;
389 #elif defined(HAVE_SQLITE3)
390 	char		*p, *path = NULL;
391 #endif
392 
393 #ifndef HAVE_MYSQL
394 	ZBX_UNUSED(dbsocket);
395 #endif
396 	/* Allow executing statements during a connection initialization. Make sure to mark transaction as failed. */
397 	if (0 != txn_level)
398 		txn_error = ZBX_DB_DOWN;
399 
400 	last_txn_error = txn_error;
401 	last_txn_level = txn_level;
402 
403 	txn_error = ZBX_DB_OK;
404 	txn_level = 0;
405 
406 #if defined(HAVE_MYSQL)
407 	ZBX_UNUSED(dbschema);
408 
409 	if (NULL == (conn = mysql_init(NULL)))
410 	{
411 		zabbix_log(LOG_LEVEL_CRIT, "cannot allocate or initialize MYSQL database connection object");
412 		exit(EXIT_FAILURE);
413 	}
414 
415 	if (1 == db_auto_increment)
416 	{
417 		/* Shadow global auto_increment variables. */
418 		/* Setting session variables requires special permissions in MySQL 8.0.14-8.0.17. */
419 
420 		if (0 != MYSQL_OPTIONS(conn, MYSQL_INIT_COMMAND, MYSQL_OPTIONS_ARGS_VOID_CAST
421 				"set @@session.auto_increment_increment=1"))
422 		{
423 			zabbix_log(LOG_LEVEL_ERR, "Cannot set auto_increment_increment option.");
424 			ret = ZBX_DB_FAIL;
425 		}
426 
427 		if (ZBX_DB_OK == ret && 0 != MYSQL_OPTIONS(conn, MYSQL_INIT_COMMAND, MYSQL_OPTIONS_ARGS_VOID_CAST
428 				"set @@session.auto_increment_offset=1"))
429 		{
430 			zabbix_log(LOG_LEVEL_ERR, "Cannot set auto_increment_offset option.");
431 			ret = ZBX_DB_FAIL;
432 		}
433 	}
434 
435 #if defined(HAVE_MYSQL_TLS)
436 	if (ZBX_DB_OK == ret && NULL != tls_connect)
437 	{
438 		unsigned int	mysql_tls_mode;
439 
440 		if (0 == strcmp(tls_connect, ZBX_DB_TLS_CONNECT_REQUIRED_TXT))
441 			mysql_tls_mode = SSL_MODE_REQUIRED;
442 		else if (0 == strcmp(tls_connect, ZBX_DB_TLS_CONNECT_VERIFY_CA_TXT))
443 			mysql_tls_mode = SSL_MODE_VERIFY_CA;
444 		else
445 			mysql_tls_mode = SSL_MODE_VERIFY_IDENTITY;
446 
447 		if (0 != mysql_options(conn, MYSQL_OPT_SSL_MODE, &mysql_tls_mode))
448 		{
449 			zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_SSL_MODE option.");
450 			ret = ZBX_DB_FAIL;
451 		}
452 	}
453 
454 	if (ZBX_DB_OK == ret && NULL != ca && 0 != mysql_options(conn, MYSQL_OPT_SSL_CA, ca))
455 	{
456 		zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_SSL_CA option.");
457 		ret = ZBX_DB_FAIL;
458 	}
459 
460 	if (ZBX_DB_OK == ret && NULL != key && 0 != mysql_options(conn, MYSQL_OPT_SSL_KEY, key))
461 	{
462 		zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_SSL_KEY option.");
463 		ret = ZBX_DB_FAIL;
464 	}
465 
466 	if (ZBX_DB_OK == ret && NULL != cert && 0 != mysql_options(conn, MYSQL_OPT_SSL_CERT, cert))
467 	{
468 		zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_SSL_CERT option.");
469 		ret = ZBX_DB_FAIL;
470 	}
471 
472 	if (ZBX_DB_OK == ret && NULL != cipher && 0 != mysql_options(conn, MYSQL_OPT_SSL_CIPHER, cipher))
473 	{
474 		zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_SSL_CIPHER option.");
475 		ret = ZBX_DB_FAIL;
476 	}
477 #if defined(HAVE_MYSQL_TLS_CIPHERSUITES)
478 	if (ZBX_DB_OK == ret && NULL != cipher_13 && 0 != mysql_options(conn, MYSQL_OPT_TLS_CIPHERSUITES, cipher_13))
479 	{
480 		zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_TLS_CIPHERSUITES option.");
481 		ret = ZBX_DB_FAIL;
482 	}
483 #else
484 	ZBX_UNUSED(cipher_13);
485 #endif
486 #elif defined(HAVE_MARIADB_TLS)
487 	ZBX_UNUSED(cipher_13);
488 
489 	if (ZBX_DB_OK == ret && NULL != tls_connect)
490 	{
491 		if (0 == strcmp(tls_connect, ZBX_DB_TLS_CONNECT_REQUIRED_TXT))
492 		{
493 			my_bool	enforce_tls = 1;
494 
495 			if (0 != mysql_optionsv(conn, MYSQL_OPT_SSL_ENFORCE, (void *)&enforce_tls))
496 			{
497 				zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_SSL_ENFORCE option.");
498 				ret = ZBX_DB_FAIL;
499 			}
500 		}
501 		else
502 		{
503 			my_bool	verify = 1;
504 
505 			if (0 != mysql_optionsv(conn, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (void *)&verify))
506 			{
507 				zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_SSL_VERIFY_SERVER_CERT option.");
508 				ret = ZBX_DB_FAIL;
509 			}
510 		}
511 	}
512 
513 	if (ZBX_DB_OK == ret && NULL != ca && 0 != mysql_optionsv(conn, MYSQL_OPT_SSL_CA, ca))
514 	{
515 		zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_SSL_CA option.");
516 		ret = ZBX_DB_FAIL;
517 	}
518 
519 	if (ZBX_DB_OK == ret && NULL != key && 0 != mysql_optionsv(conn, MYSQL_OPT_SSL_KEY, key))
520 	{
521 		zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_SSL_KEY option.");
522 		ret = ZBX_DB_FAIL;
523 	}
524 
525 	if (ZBX_DB_OK == ret && NULL != cert && 0 != mysql_optionsv(conn, MYSQL_OPT_SSL_CERT, cert))
526 	{
527 		zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_SSL_CERT option.");
528 		ret = ZBX_DB_FAIL;
529 	}
530 
531 	if (ZBX_DB_OK == ret && NULL != cipher && 0 != mysql_optionsv(conn, MYSQL_OPT_SSL_CIPHER, cipher))
532 	{
533 		zabbix_log(LOG_LEVEL_ERR, "Cannot set MYSQL_OPT_SSL_CIPHER option.");
534 		ret = ZBX_DB_FAIL;
535 	}
536 #else
537 	ZBX_UNUSED(tls_connect);
538 	ZBX_UNUSED(cert);
539 	ZBX_UNUSED(key);
540 	ZBX_UNUSED(ca);
541 	ZBX_UNUSED(cipher);
542 	ZBX_UNUSED(cipher_13);
543 #endif
544 	if (ZBX_DB_OK == ret &&
545 			NULL == mysql_real_connect(conn, host, user, password, dbname, port, dbsocket,
546 				CLIENT_MULTI_STATEMENTS))
547 	{
548 		zbx_db_errlog(ERR_Z3001, mysql_errno(conn), mysql_error(conn), dbname);
549 		ret = ZBX_DB_FAIL;
550 	}
551 
552 	/* The RECONNECT option setting is placed here, AFTER the connection	*/
553 	/* is made, due to a bug in MySQL versions prior to 5.1.6 where it	*/
554 	/* reset the options value to the default, regardless of what it was	*/
555 	/* set to prior to the connection. MySQL allows changing connection	*/
556 	/* options on an open connection, so setting it here is safe.		*/
557 
558 	if (ZBX_DB_OK == ret && 0 != mysql_options(conn, MYSQL_OPT_RECONNECT, &mysql_reconnect))
559 		zabbix_log(LOG_LEVEL_WARNING, "Cannot set MySQL reconnect option.");
560 
561 	/* in contrast to "set names utf8" results of this call will survive auto-reconnects */
562 	if (ZBX_DB_OK == ret && 0 != mysql_set_character_set(conn, "utf8"))
563 		zabbix_log(LOG_LEVEL_WARNING, "cannot set MySQL character set to \"utf8\"");
564 
565 	if (ZBX_DB_OK == ret && 0 != mysql_autocommit(conn, 1))
566 	{
567 		zbx_db_errlog(ERR_Z3001, mysql_errno(conn), mysql_error(conn), dbname);
568 		ret = ZBX_DB_FAIL;
569 	}
570 
571 	if (ZBX_DB_OK == ret && 0 != mysql_select_db(conn, dbname))
572 	{
573 		zbx_db_errlog(ERR_Z3001, mysql_errno(conn), mysql_error(conn), dbname);
574 		ret = ZBX_DB_FAIL;
575 	}
576 
577 	if (ZBX_DB_FAIL == ret && SUCCEED == is_recoverable_mysql_error())
578 		ret = ZBX_DB_DOWN;
579 
580 #elif defined(HAVE_ORACLE)
581 	ZBX_UNUSED(dbschema);
582 	ZBX_UNUSED(tls_connect);
583 	ZBX_UNUSED(cert);
584 	ZBX_UNUSED(key);
585 	ZBX_UNUSED(ca);
586 	ZBX_UNUSED(cipher);
587 	ZBX_UNUSED(cipher_13);
588 
589 	memset(&oracle, 0, sizeof(oracle));
590 
591 	zbx_vector_ptr_create(&oracle.db_results);
592 
593 	/* connection string format: [//]host[:port][/service name] */
594 
595 	if ('\0' != *host)
596 	{
597 		/* Easy Connect method */
598 		connect = zbx_strdcatf(connect, "//%s", host);
599 		if (0 != port)
600 			connect = zbx_strdcatf(connect, ":%d", port);
601 		if ('\0' != *dbname)
602 			connect = zbx_strdcatf(connect, "/%s", dbname);
603 	}
604 	else
605 	{
606 		/* Net Service Name method */
607 		connect = zbx_strdup(connect, dbname);
608 	}
609 
610 	while (ZBX_DB_OK == ret)
611 	{
612 		/* initialize environment */
613 		if (OCI_SUCCESS == (err = OCIEnvNlsCreate((OCIEnv **)&oracle.envhp, (ub4)OCI_DEFAULT, (dvoid *)0,
614 				(dvoid * (*)(dvoid *,size_t))0, (dvoid * (*)(dvoid *, dvoid *, size_t))0,
615 				(void (*)(dvoid *, dvoid *))0, (size_t)0, (dvoid **)0, csid, csid)))
616 		{
617 			if (0 != csid)
618 				break;	/* environment with UTF8 character set successfully created */
619 
620 			/* try to find out the id of UTF8 character set */
621 			if (0 == (csid = OCINlsCharSetNameToId(oracle.envhp, (const oratext *)"UTF8")))
622 			{
623 				zabbix_log(LOG_LEVEL_WARNING, "Cannot find out the ID of \"UTF8\" character set."
624 						" Relying on current \"NLS_LANG\" settings.");
625 				break;	/* use default environment with character set derived from NLS_LANG */
626 			}
627 
628 			/* get rid of this environment to create a better one on the next iteration */
629 			OCIHandleFree((dvoid *)oracle.envhp, OCI_HTYPE_ENV);
630 			oracle.envhp = NULL;
631 		}
632 		else
633 		{
634 			zbx_db_errlog(ERR_Z3001, err, zbx_oci_error(err, NULL), connect);
635 			ret = ZBX_DB_FAIL;
636 		}
637 	}
638 
639 	if (ZBX_DB_OK == ret)
640 	{
641 		/* allocate an error handle */
642 		(void)OCIHandleAlloc((dvoid *)oracle.envhp, (dvoid **)&oracle.errhp, OCI_HTYPE_ERROR,
643 				(size_t)0, (dvoid **)0);
644 
645 		/* get the session */
646 		err = OCILogon2(oracle.envhp, oracle.errhp, &oracle.svchp,
647 				(text *)user, (ub4)(NULL != user ? strlen(user) : 0),
648 				(text *)password, (ub4)(NULL != password ? strlen(password) : 0),
649 				(text *)connect, (ub4)strlen(connect),
650 				OCI_DEFAULT);
651 
652 		switch (err)
653 		{
654 			case OCI_SUCCESS_WITH_INFO:
655 				zabbix_log(LOG_LEVEL_WARNING, "%s", zbx_oci_error(err, NULL));
656 				/* break; is not missing here */
657 				ZBX_FALLTHROUGH;
658 			case OCI_SUCCESS:
659 				err = OCIAttrGet((void *)oracle.svchp, OCI_HTYPE_SVCCTX, (void *)&oracle.srvhp,
660 						(ub4 *)0, OCI_ATTR_SERVER, oracle.errhp);
661 		}
662 
663 		if (OCI_SUCCESS != err)
664 		{
665 			zbx_db_errlog(ERR_Z3001, err, zbx_oci_error(err, NULL), connect);
666 			ret = ZBX_DB_DOWN;
667 		}
668 	}
669 
670 	if (ZBX_DB_OK == ret)
671 	{
672 		/* initialize statement handle */
673 		err = OCIHandleAlloc((dvoid *)oracle.envhp, (dvoid **)&oracle.stmthp, OCI_HTYPE_STMT,
674 				(size_t)0, (dvoid **)0);
675 
676 		if (OCI_SUCCESS != err)
677 		{
678 			zbx_db_errlog(ERR_Z3001, err, zbx_oci_error(err, NULL), connect);
679 			ret = ZBX_DB_DOWN;
680 		}
681 	}
682 
683 	if (ZBX_DB_OK == ret)
684 	{
685 		if (0 < (ret = zbx_db_execute("alter session set nls_numeric_characters='. '")))
686 			ret = ZBX_DB_OK;
687 	}
688 
689 	zbx_free(connect);
690 #elif defined(HAVE_POSTGRESQL)
691 	ZBX_UNUSED(cipher);
692 	ZBX_UNUSED(cipher_13);
693 
694 	if (NULL != tls_connect)
695 	{
696 		keywords[i] = "sslmode";
697 
698 		if (0 == strcmp(tls_connect, ZBX_DB_TLS_CONNECT_REQUIRED_TXT))
699 			values[i++] = "require";
700 		else if (0 == strcmp(tls_connect, ZBX_DB_TLS_CONNECT_VERIFY_CA_TXT))
701 			values[i++] = "verify-ca";
702 		else
703 			values[i++] = "verify-full";
704 	}
705 
706 	if (NULL != cert)
707 	{
708 		keywords[i] = "sslcert";
709 		values[i++] = cert;
710 	}
711 
712 	if (NULL != key)
713 	{
714 		keywords[i] = "sslkey";
715 		values[i++] = key;
716 	}
717 
718 	if (NULL != ca)
719 	{
720 		keywords[i] = "sslrootcert";
721 		values[i++] = ca;
722 	}
723 
724 	if (NULL != host)
725 	{
726 		keywords[i] = "host";
727 		values[i++] = host;
728 	}
729 
730 	if (NULL != dbname)
731 	{
732 		keywords[i] = "dbname";
733 		values[i++] = dbname;
734 	}
735 
736 	if (NULL != user)
737 	{
738 		keywords[i] = "user";
739 		values[i++] = user;
740 	}
741 
742 	if (NULL != password)
743 	{
744 		keywords[i] = "password";
745 		values[i++] = password;
746 	}
747 
748 	if (0 != port)
749 	{
750 		keywords[i] = "port";
751 		values[i++] = cport = zbx_dsprintf(cport, "%d", port);
752 	}
753 
754 	keywords[i] = NULL;
755 	values[i] = NULL;
756 
757 	conn = PQconnectdbParams(keywords, values, 0);
758 
759 	zbx_free(cport);
760 
761 	/* check to see that the backend connection was successfully made */
762 	if (CONNECTION_OK != PQstatus(conn))
763 	{
764 		zbx_db_errlog(ERR_Z3001, 0, PQerrorMessage(conn), dbname);
765 		ret = ZBX_DB_DOWN;
766 		goto out;
767 	}
768 
769 	if (NULL != dbschema && '\0' != *dbschema)
770 	{
771 		char	*dbschema_esc;
772 
773 		dbschema_esc = zbx_db_dyn_escape_string(dbschema, ZBX_SIZE_T_MAX, ZBX_SIZE_T_MAX, ESCAPE_SEQUENCE_ON);
774 		if (ZBX_DB_DOWN == (rc = zbx_db_execute("set schema '%s'", dbschema_esc)) || ZBX_DB_FAIL == rc)
775 			ret = rc;
776 		zbx_free(dbschema_esc);
777 	}
778 
779 	if (ZBX_DB_FAIL == ret || ZBX_DB_DOWN == ret)
780 		goto out;
781 
782 	result = zbx_db_select("select oid from pg_type where typname='bytea'");
783 
784 	if ((DB_RESULT)ZBX_DB_DOWN == result || NULL == result)
785 	{
786 		ret = (NULL == result) ? ZBX_DB_FAIL : ZBX_DB_DOWN;
787 		goto out;
788 	}
789 
790 	if (NULL != (row = zbx_db_fetch(result)))
791 		ZBX_PG_BYTEAOID = atoi(row[0]);
792 	DBfree_result(result);
793 
794 	/* disable "nonstandard use of \' in a string literal" warning */
795 	if (0 < (ret = zbx_db_execute("set escape_string_warning to off")))
796 		ret = ZBX_DB_OK;
797 
798 	if (ZBX_DB_OK != ret)
799 		goto out;
800 
801 	/* increase float precision */
802 	if (0 < (ret = zbx_db_execute("set extra_float_digits to 3")))
803 		ret = ZBX_DB_OK;
804 
805 	if (ZBX_DB_OK != ret)
806 		goto out;
807 
808 	result = zbx_db_select("show standard_conforming_strings");
809 
810 	if ((DB_RESULT)ZBX_DB_DOWN == result || NULL == result)
811 	{
812 		ret = (NULL == result) ? ZBX_DB_FAIL : ZBX_DB_DOWN;
813 		goto out;
814 	}
815 
816 	if (NULL != (row = zbx_db_fetch(result)))
817 		ZBX_PG_ESCAPE_BACKSLASH = (0 == strcmp(row[0], "off"));
818 	DBfree_result(result);
819 
820 	if (90000 <= ZBX_PG_SVERSION)
821 	{
822 		/* change the output format for values of type bytea from hex (the default) to escape */
823 		if (0 < (ret = zbx_db_execute("set bytea_output=escape")))
824 			ret = ZBX_DB_OK;
825 	}
826 out:
827 #elif defined(HAVE_SQLITE3)
828 	ZBX_UNUSED(host);
829 	ZBX_UNUSED(user);
830 	ZBX_UNUSED(password);
831 	ZBX_UNUSED(dbschema);
832 	ZBX_UNUSED(port);
833 	ZBX_UNUSED(tls_connect);
834 	ZBX_UNUSED(cert);
835 	ZBX_UNUSED(key);
836 	ZBX_UNUSED(ca);
837 	ZBX_UNUSED(cipher);
838 	ZBX_UNUSED(cipher_13);
839 #ifdef HAVE_FUNCTION_SQLITE3_OPEN_V2
840 	if (SQLITE_OK != sqlite3_open_v2(dbname, &conn, SQLITE_OPEN_READWRITE, NULL))
841 #else
842 	if (SQLITE_OK != sqlite3_open(dbname, &conn))
843 #endif
844 	{
845 		zbx_db_errlog(ERR_Z3001, 0, sqlite3_errmsg(conn), dbname);
846 		ret = ZBX_DB_DOWN;
847 		goto out;
848 	}
849 
850 	/* do not return SQLITE_BUSY immediately, wait for N ms */
851 	sqlite3_busy_timeout(conn, SEC_PER_MIN * 1000);
852 
853 	if (0 < (ret = zbx_db_execute("pragma synchronous=0")))
854 		ret = ZBX_DB_OK;
855 
856 	if (ZBX_DB_OK != ret)
857 		goto out;
858 
859 	if (0 < (ret = zbx_db_execute("pragma temp_store=2")))
860 		ret = ZBX_DB_OK;
861 
862 	if (ZBX_DB_OK != ret)
863 		goto out;
864 
865 	path = zbx_strdup(NULL, dbname);
866 
867 	if (NULL != (p = strrchr(path, '/')))
868 		*++p = '\0';
869 	else
870 		*path = '\0';
871 
872 	if (0 < (ret = zbx_db_execute("pragma temp_store_directory='%s'", path)))
873 		ret = ZBX_DB_OK;
874 
875 	zbx_free(path);
876 out:
877 #endif	/* HAVE_SQLITE3 */
878 	if (ZBX_DB_OK != ret)
879 		zbx_db_close();
880 
881 	txn_error = last_txn_error;
882 	txn_level = last_txn_level;
883 
884 	return ret;
885 }
886 
zbx_db_init(const char * dbname,const char * const dbschema,char ** error)887 int	zbx_db_init(const char *dbname, const char *const dbschema, char **error)
888 {
889 #ifdef HAVE_SQLITE3
890 	zbx_stat_t	buf;
891 
892 	if (0 != zbx_stat(dbname, &buf))
893 	{
894 		zabbix_log(LOG_LEVEL_WARNING, "cannot open database file \"%s\": %s", dbname, zbx_strerror(errno));
895 		zabbix_log(LOG_LEVEL_WARNING, "creating database ...");
896 
897 		if (SQLITE_OK != sqlite3_open(dbname, &conn))
898 		{
899 			zbx_db_errlog(ERR_Z3002, 0, sqlite3_errmsg(conn), dbname);
900 			*error = zbx_strdup(*error, "cannot open database");
901 			return FAIL;
902 		}
903 
904 		if (SUCCEED != zbx_mutex_create(&sqlite_access, ZBX_MUTEX_SQLITE3, error))
905 			return FAIL;
906 
907 		zbx_db_execute("%s", dbschema);
908 		zbx_db_close();
909 		return SUCCEED;
910 	}
911 
912 	return zbx_mutex_create(&sqlite_access, ZBX_MUTEX_SQLITE3, error);
913 #else	/* not HAVE_SQLITE3 */
914 	ZBX_UNUSED(dbname);
915 	ZBX_UNUSED(dbschema);
916 	ZBX_UNUSED(error);
917 
918 	return SUCCEED;
919 #endif	/* HAVE_SQLITE3 */
920 }
921 
zbx_db_deinit(void)922 void	zbx_db_deinit(void)
923 {
924 #ifdef HAVE_SQLITE3
925 	zbx_mutex_destroy(&sqlite_access);
926 #endif
927 }
928 
zbx_db_close(void)929 void	zbx_db_close(void)
930 {
931 #if defined(HAVE_MYSQL)
932 	if (NULL != conn)
933 	{
934 		mysql_close(conn);
935 		conn = NULL;
936 	}
937 #elif defined(HAVE_ORACLE)
938 	if (0 != oracle.db_results.values_num)
939 	{
940 		int	i;
941 
942 		zabbix_log(LOG_LEVEL_WARNING, "cannot process queries: database is closed");
943 
944 		for (i = 0; i < oracle.db_results.values_num; i++)
945 		{
946 			/* deallocate all handles before environment is deallocated */
947 			OCI_DBclean_result(oracle.db_results.values[i]);
948 		}
949 	}
950 
951 	/* deallocate statement handle */
952 	if (NULL != oracle.stmthp)
953 	{
954 		OCIHandleFree((dvoid *)oracle.stmthp, OCI_HTYPE_STMT);
955 		oracle.stmthp = NULL;
956 	}
957 
958 	if (NULL != oracle.svchp)
959 	{
960 		OCILogoff(oracle.svchp, oracle.errhp);
961 		oracle.svchp = NULL;
962 	}
963 
964 	if (NULL != oracle.errhp)
965 	{
966 		OCIHandleFree(oracle.errhp, OCI_HTYPE_ERROR);
967 		oracle.errhp = NULL;
968 	}
969 
970 	if (NULL != oracle.srvhp)
971 	{
972 		OCIHandleFree(oracle.srvhp, OCI_HTYPE_SERVER);
973 		oracle.srvhp = NULL;
974 	}
975 
976 	if (NULL != oracle.envhp)
977 	{
978 		/* delete the environment handle, which deallocates all other handles associated with it */
979 		OCIHandleFree((dvoid *)oracle.envhp, OCI_HTYPE_ENV);
980 		oracle.envhp = NULL;
981 	}
982 
983 	zbx_vector_ptr_destroy(&oracle.db_results);
984 #elif defined(HAVE_POSTGRESQL)
985 	if (NULL != conn)
986 	{
987 		PQfinish(conn);
988 		conn = NULL;
989 	}
990 #elif defined(HAVE_SQLITE3)
991 	if (NULL != conn)
992 	{
993 		sqlite3_close(conn);
994 		conn = NULL;
995 	}
996 #endif
997 }
998 
999 /******************************************************************************
1000  *                                                                            *
1001  * Function: zbx_db_begin                                                     *
1002  *                                                                            *
1003  * Purpose: start transaction                                                 *
1004  *                                                                            *
1005  * Comments: do nothing if DB does not support transactions                   *
1006  *                                                                            *
1007  ******************************************************************************/
zbx_db_begin(void)1008 int	zbx_db_begin(void)
1009 {
1010 	int	rc = ZBX_DB_OK;
1011 
1012 	if (txn_level > 0)
1013 	{
1014 		zabbix_log(LOG_LEVEL_CRIT, "ERROR: nested transaction detected. Please report it to Zabbix Team.");
1015 		assert(0);
1016 	}
1017 
1018 	txn_level++;
1019 
1020 #if defined(HAVE_MYSQL) || defined(HAVE_POSTGRESQL)
1021 	rc = zbx_db_execute("begin;");
1022 #elif defined(HAVE_SQLITE3)
1023 	zbx_mutex_lock(sqlite_access);
1024 	rc = zbx_db_execute("begin;");
1025 #endif
1026 
1027 	if (ZBX_DB_DOWN == rc)
1028 		txn_level--;
1029 
1030 	return rc;
1031 }
1032 
1033 /******************************************************************************
1034  *                                                                            *
1035  * Function: zbx_db_commit                                                    *
1036  *                                                                            *
1037  * Purpose: commit transaction                                                *
1038  *                                                                            *
1039  * Comments: do nothing if DB does not support transactions                   *
1040  *                                                                            *
1041  ******************************************************************************/
zbx_db_commit(void)1042 int	zbx_db_commit(void)
1043 {
1044 	int	rc = ZBX_DB_OK;
1045 #ifdef HAVE_ORACLE
1046 	sword	err;
1047 #endif
1048 
1049 	if (0 == txn_level)
1050 	{
1051 		zabbix_log(LOG_LEVEL_CRIT, "ERROR: commit without transaction."
1052 				" Please report it to Zabbix Team.");
1053 		assert(0);
1054 	}
1055 
1056 	if (ZBX_DB_OK != txn_error)
1057 		return ZBX_DB_FAIL; /* commit called on failed transaction */
1058 
1059 #if defined(HAVE_ORACLE)
1060 	if (OCI_SUCCESS != (err = OCITransCommit(oracle.svchp, oracle.errhp, OCI_DEFAULT)))
1061 		rc = OCI_handle_sql_error(ERR_Z3005, err, "commit failed");
1062 #elif defined(HAVE_MYSQL) || defined(HAVE_POSTGRESQL) || defined(HAVE_SQLITE3)
1063 	rc = zbx_db_execute("commit;");
1064 #endif
1065 
1066 	if (ZBX_DB_OK > rc) { /* commit failed */
1067 		txn_error = rc;
1068 		return rc;
1069 	}
1070 
1071 #ifdef HAVE_SQLITE3
1072 	zbx_mutex_unlock(sqlite_access);
1073 #endif
1074 
1075 	txn_level--;
1076 	txn_end_error = ZBX_DB_OK;
1077 
1078 	return rc;
1079 }
1080 
1081 /******************************************************************************
1082  *                                                                            *
1083  * Function: zbx_db_rollback                                                  *
1084  *                                                                            *
1085  * Purpose: rollback transaction                                              *
1086  *                                                                            *
1087  * Comments: do nothing if DB does not support transactions                   *
1088  *                                                                            *
1089  ******************************************************************************/
zbx_db_rollback(void)1090 int	zbx_db_rollback(void)
1091 {
1092 	int	rc = ZBX_DB_OK, last_txn_error;
1093 #ifdef HAVE_ORACLE
1094 	sword	err;
1095 #endif
1096 
1097 	if (0 == txn_level)
1098 	{
1099 		zabbix_log(LOG_LEVEL_CRIT, "ERROR: rollback without transaction."
1100 				" Please report it to Zabbix Team.");
1101 		assert(0);
1102 	}
1103 
1104 	last_txn_error = txn_error;
1105 
1106 	/* allow rollback of failed transaction */
1107 	txn_error = ZBX_DB_OK;
1108 
1109 #if defined(HAVE_MYSQL) || defined(HAVE_POSTGRESQL)
1110 	rc = zbx_db_execute("rollback;");
1111 #elif defined(HAVE_ORACLE)
1112 	if (OCI_SUCCESS != (err = OCITransRollback(oracle.svchp, oracle.errhp, OCI_DEFAULT)))
1113 		rc = OCI_handle_sql_error(ERR_Z3005, err, "rollback failed");
1114 #elif defined(HAVE_SQLITE3)
1115 	rc = zbx_db_execute("rollback;");
1116 	zbx_mutex_unlock(sqlite_access);
1117 #endif
1118 
1119 	/* There is no way to recover from rollback errors, so there is no need to preserve transaction level / error. */
1120 	txn_level = 0;
1121 	txn_error = ZBX_DB_OK;
1122 
1123 	if (ZBX_DB_FAIL == rc)
1124 		txn_end_error = ZBX_DB_FAIL;
1125 	else
1126 		txn_end_error = last_txn_error;	/* error that caused rollback */
1127 
1128 	return rc;
1129 }
1130 
zbx_db_txn_level(void)1131 int	zbx_db_txn_level(void)
1132 {
1133 	return txn_level;
1134 }
1135 
zbx_db_txn_error(void)1136 int	zbx_db_txn_error(void)
1137 {
1138 	return txn_error;
1139 }
1140 
zbx_db_txn_end_error(void)1141 int	zbx_db_txn_end_error(void)
1142 {
1143 	return txn_end_error;
1144 }
1145 
1146 #ifdef HAVE_ORACLE
zbx_oracle_statement_prepare(const char * sql)1147 static sword	zbx_oracle_statement_prepare(const char *sql)
1148 {
1149 	return OCIStmtPrepare(oracle.stmthp, oracle.errhp, (text *)sql, (ub4)strlen((char *)sql), (ub4)OCI_NTV_SYNTAX,
1150 			(ub4)OCI_DEFAULT);
1151 }
1152 
zbx_oracle_statement_execute(ub4 iters,ub4 * nrows)1153 static sword	zbx_oracle_statement_execute(ub4 iters, ub4 *nrows)
1154 {
1155 	sword	err;
1156 
1157 	if (OCI_SUCCESS == (err = OCIStmtExecute(oracle.svchp, oracle.stmthp, oracle.errhp, iters, (ub4)0,
1158 			(CONST OCISnapshot *)NULL, (OCISnapshot *)NULL,
1159 			0 == txn_level ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT)))
1160 	{
1161 		err = OCIAttrGet((void *)oracle.stmthp, OCI_HTYPE_STMT, nrows, (ub4 *)0, OCI_ATTR_ROW_COUNT,
1162 				oracle.errhp);
1163 	}
1164 
1165 	return err;
1166 }
1167 #endif
1168 
1169 #ifdef HAVE_ORACLE
zbx_db_statement_prepare(const char * sql)1170 int	zbx_db_statement_prepare(const char *sql)
1171 {
1172 	sword	err;
1173 	int	ret = ZBX_DB_OK;
1174 
1175 	if (0 == txn_level)
1176 		zabbix_log(LOG_LEVEL_DEBUG, "query without transaction detected");
1177 
1178 	if (ZBX_DB_OK != txn_error)
1179 	{
1180 		zabbix_log(LOG_LEVEL_DEBUG, "ignoring query [txnlev:%d] within failed transaction", txn_level);
1181 		return ZBX_DB_FAIL;
1182 	}
1183 
1184 	zabbix_log(LOG_LEVEL_DEBUG, "query [txnlev:%d] [%s]", txn_level, sql);
1185 
1186 	if (OCI_SUCCESS != (err = zbx_oracle_statement_prepare(sql)))
1187 		ret = OCI_handle_sql_error(ERR_Z3005, err, sql);
1188 
1189 	if (ZBX_DB_FAIL == ret && 0 < txn_level)
1190 	{
1191 		zabbix_log(LOG_LEVEL_DEBUG, "query [%s] failed, setting transaction as failed", sql);
1192 		txn_error = ZBX_DB_FAIL;
1193 	}
1194 
1195 	return ret;
1196 }
1197 
1198 /******************************************************************************
1199  *                                                                            *
1200  * Function: db_bind_dynamic_cb                                               *
1201  *                                                                            *
1202  * Purpose: callback function used by dynamic parameter binding               *
1203  *                                                                            *
1204  ******************************************************************************/
db_bind_dynamic_cb(dvoid * ctxp,OCIBind * bindp,ub4 iter,ub4 index,dvoid ** bufpp,ub4 * alenp,ub1 * piecep,dvoid ** indpp)1205 static sb4 db_bind_dynamic_cb(dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 *alenp, ub1 *piecep,
1206 		dvoid **indpp)
1207 {
1208 	zbx_db_bind_context_t	*context = (zbx_db_bind_context_t *)ctxp;
1209 
1210 	ZBX_UNUSED(bindp);
1211 	ZBX_UNUSED(index);
1212 
1213 	switch (context->type)
1214 	{
1215 		case ZBX_TYPE_ID: /* handle 0 -> NULL conversion */
1216 			if (0 == context->rows[iter][context->position].ui64)
1217 			{
1218 				*bufpp = NULL;
1219 				*alenp = 0;
1220 				break;
1221 			}
1222 			ZBX_FALLTHROUGH;
1223 		case ZBX_TYPE_UINT:
1224 			*bufpp = &((OCINumber *)context->data)[iter];
1225 			*alenp = sizeof(OCINumber);
1226 			break;
1227 		case ZBX_TYPE_INT:
1228 			*bufpp = &context->rows[iter][context->position].i32;
1229 			*alenp = sizeof(int);
1230 			break;
1231 		case ZBX_TYPE_FLOAT:
1232 			*bufpp = &context->rows[iter][context->position].dbl;
1233 			*alenp = sizeof(double);
1234 			break;
1235 		case ZBX_TYPE_CHAR:
1236 		case ZBX_TYPE_TEXT:
1237 		case ZBX_TYPE_SHORTTEXT:
1238 		case ZBX_TYPE_LONGTEXT:
1239 			*bufpp = context->rows[iter][context->position].str;
1240 			*alenp = ((size_t *)context->data)[iter];
1241 			break;
1242 		default:
1243 			return FAIL;
1244 	}
1245 
1246 	*indpp = NULL;
1247 	*piecep = OCI_ONE_PIECE;
1248 
1249 	return OCI_CONTINUE;
1250 }
1251 
1252 /******************************************************************************
1253  *                                                                            *
1254  * Function: zbx_db_bind_parameter_dyn                                        *
1255  *                                                                            *
1256  * Purpose: performs dynamic parameter binding, converting value if necessary *
1257  *                                                                            *
1258  * Parameters: context  - [OUT] the bind context                              *
1259  *             position - [IN] the parameter position                         *
1260  *             type     - [IN] the parameter type (ZBX_TYPE_* )               *
1261  *             rows     - [IN] the data to bind - array of rows,              *
1262  *                             each row being an array of columns             *
1263  *             rows_num - [IN] the number of rows in the data                 *
1264  *                                                                            *
1265  ******************************************************************************/
zbx_db_bind_parameter_dyn(zbx_db_bind_context_t * context,int position,unsigned char type,zbx_db_value_t ** rows,int rows_num)1266 int	zbx_db_bind_parameter_dyn(zbx_db_bind_context_t *context, int position, unsigned char type,
1267 		zbx_db_value_t **rows, int rows_num)
1268 {
1269 	int		i, ret = ZBX_DB_OK;
1270 	size_t		*sizes;
1271 	sword		err;
1272 	OCINumber	*values;
1273 	ub2		data_type;
1274 	OCIBind		*bindhp = NULL;
1275 
1276 	context->position = position;
1277 	context->rows = rows;
1278 	context->data = NULL;
1279 	context->type = type;
1280 
1281 	switch (type)
1282 	{
1283 		case ZBX_TYPE_ID:
1284 		case ZBX_TYPE_UINT:
1285 			values = (OCINumber *)zbx_malloc(NULL, sizeof(OCINumber) * rows_num);
1286 
1287 			for (i = 0; i < rows_num; i++)
1288 			{
1289 				err = OCINumberFromInt(oracle.errhp, &rows[i][position].ui64, sizeof(zbx_uint64_t),
1290 						OCI_NUMBER_UNSIGNED, &values[i]);
1291 
1292 				if (OCI_SUCCESS != err)
1293 				{
1294 					ret = OCI_handle_sql_error(ERR_Z3007, err, NULL);
1295 					goto out;
1296 				}
1297 			}
1298 
1299 			context->data = (OCINumber *)values;
1300 			context->size_max = sizeof(OCINumber);
1301 			data_type = SQLT_VNU;
1302 			break;
1303 		case ZBX_TYPE_INT:
1304 			context->size_max = sizeof(int);
1305 			data_type = SQLT_INT;
1306 			break;
1307 		case ZBX_TYPE_FLOAT:
1308 			context->size_max = sizeof(double);
1309 			data_type = SQLT_BDOUBLE;
1310 			break;
1311 		case ZBX_TYPE_CHAR:
1312 		case ZBX_TYPE_TEXT:
1313 		case ZBX_TYPE_SHORTTEXT:
1314 		case ZBX_TYPE_LONGTEXT:
1315 			sizes = (size_t *)zbx_malloc(NULL, sizeof(size_t) * rows_num);
1316 			context->size_max = 0;
1317 
1318 			for (i = 0; i < rows_num; i++)
1319 			{
1320 				sizes[i] = strlen(rows[i][position].str);
1321 
1322 				if (sizes[i] > context->size_max)
1323 					context->size_max = sizes[i];
1324 			}
1325 
1326 			context->data = sizes;
1327 			data_type = SQLT_LNG;
1328 			break;
1329 		default:
1330 			THIS_SHOULD_NEVER_HAPPEN;
1331 			exit(EXIT_FAILURE);
1332 	}
1333 
1334 	err = OCIBindByPos(oracle.stmthp, &bindhp, oracle.errhp, context->position + 1, NULL, context->size_max,
1335 			data_type, NULL, NULL, NULL, 0, NULL, (ub4)OCI_DATA_AT_EXEC);
1336 
1337 	if (OCI_SUCCESS != err)
1338 	{
1339 		ret = OCI_handle_sql_error(ERR_Z3007, err, NULL);
1340 
1341 		if (ZBX_DB_FAIL == ret && 0 < txn_level)
1342 		{
1343 			zabbix_log(LOG_LEVEL_DEBUG, "query failed, setting transaction as failed");
1344 			txn_error = ZBX_DB_FAIL;
1345 		}
1346 
1347 		goto out;
1348 	}
1349 
1350 	err = OCIBindDynamic(bindhp, oracle.errhp, (dvoid *)context, db_bind_dynamic_cb, NULL, NULL);
1351 
1352 	if (OCI_SUCCESS != err)
1353 	{
1354 		ret = OCI_handle_sql_error(ERR_Z3007, err, NULL);
1355 
1356 		if (ZBX_DB_FAIL == ret && 0 < txn_level)
1357 		{
1358 			zabbix_log(LOG_LEVEL_DEBUG, "query failed, setting transaction as failed");
1359 			txn_error = ZBX_DB_FAIL;
1360 		}
1361 
1362 		goto out;
1363 	}
1364 out:
1365 	if (ret != ZBX_DB_OK)
1366 		zbx_db_clean_bind_context(context);
1367 
1368 	return ret;
1369 }
1370 
zbx_db_clean_bind_context(zbx_db_bind_context_t * context)1371 void	zbx_db_clean_bind_context(zbx_db_bind_context_t *context)
1372 {
1373 	zbx_free(context->data);
1374 }
1375 
zbx_db_statement_execute(int iters)1376 int	zbx_db_statement_execute(int iters)
1377 {
1378 	sword	err;
1379 	ub4	nrows;
1380 	int	ret;
1381 
1382 	if (ZBX_DB_OK != txn_error)
1383 	{
1384 		zabbix_log(LOG_LEVEL_DEBUG, "ignoring query [txnlev:%d] within failed transaction", txn_level);
1385 		ret = ZBX_DB_FAIL;
1386 		goto out;
1387 	}
1388 
1389 	if (OCI_SUCCESS != (err = zbx_oracle_statement_execute(iters, &nrows)))
1390 		ret = OCI_handle_sql_error(ERR_Z3007, err, NULL);
1391 	else
1392 		ret = (int)nrows;
1393 
1394 	if (ZBX_DB_FAIL == ret && 0 < txn_level)
1395 	{
1396 		zabbix_log(LOG_LEVEL_DEBUG, "query failed, setting transaction as failed");
1397 		txn_error = ZBX_DB_FAIL;
1398 	}
1399 out:
1400 	zabbix_log(LOG_LEVEL_DEBUG, "%s():%d", __func__, ret);
1401 
1402 	return ret;
1403 }
1404 #endif
1405 
1406 /******************************************************************************
1407  *                                                                            *
1408  * Function: zbx_db_vexecute                                                  *
1409  *                                                                            *
1410  * Purpose: Execute SQL statement. For non-select statements only.            *
1411  *                                                                            *
1412  * Return value: ZBX_DB_FAIL (on error) or ZBX_DB_DOWN (on recoverable error) *
1413  *               or number of rows affected (on success)                      *
1414  *                                                                            *
1415  ******************************************************************************/
zbx_db_vexecute(const char * fmt,va_list args)1416 int	zbx_db_vexecute(const char *fmt, va_list args)
1417 {
1418 	char	*sql = NULL;
1419 	int	ret = ZBX_DB_OK;
1420 	double	sec = 0;
1421 #if defined(HAVE_MYSQL)
1422 #elif defined(HAVE_ORACLE)
1423 	sword		err = OCI_SUCCESS;
1424 #elif defined(HAVE_POSTGRESQL)
1425 	PGresult	*result;
1426 	char		*error = NULL;
1427 #elif defined(HAVE_SQLITE3)
1428 	int		err;
1429 	char		*error = NULL;
1430 #endif
1431 
1432 	if (0 != CONFIG_LOG_SLOW_QUERIES)
1433 		sec = zbx_time();
1434 
1435 	sql = zbx_dvsprintf(sql, fmt, args);
1436 
1437 	if (0 == txn_level)
1438 		zabbix_log(LOG_LEVEL_DEBUG, "query without transaction detected");
1439 
1440 	if (ZBX_DB_OK != txn_error)
1441 	{
1442 		zabbix_log(LOG_LEVEL_DEBUG, "ignoring query [txnlev:%d] [%s] within failed transaction", txn_level,
1443 				sql);
1444 		ret = ZBX_DB_FAIL;
1445 		goto clean;
1446 	}
1447 
1448 	zabbix_log(LOG_LEVEL_DEBUG, "query [txnlev:%d] [%s]", txn_level, sql);
1449 
1450 #if defined(HAVE_MYSQL)
1451 	if (NULL == conn)
1452 	{
1453 		zbx_db_errlog(ERR_Z3003, 0, NULL, NULL);
1454 		ret = ZBX_DB_FAIL;
1455 	}
1456 	else
1457 	{
1458 		if (0 != mysql_query(conn, sql))
1459 		{
1460 			zbx_db_errlog(ERR_Z3005, mysql_errno(conn), mysql_error(conn), sql);
1461 
1462 			ret = (SUCCEED == is_recoverable_mysql_error() ? ZBX_DB_DOWN : ZBX_DB_FAIL);
1463 		}
1464 		else
1465 		{
1466 			int	status;
1467 
1468 			do
1469 			{
1470 				if (0 != mysql_field_count(conn))
1471 				{
1472 					zabbix_log(LOG_LEVEL_DEBUG, "cannot retrieve result set");
1473 					break;
1474 				}
1475 
1476 				ret += (int)mysql_affected_rows(conn);
1477 
1478 				/* more results? 0 = yes (keep looping), -1 = no, >0 = error */
1479 				if (0 < (status = mysql_next_result(conn)))
1480 				{
1481 					zbx_db_errlog(ERR_Z3005, mysql_errno(conn), mysql_error(conn), sql);
1482 					ret = (SUCCEED == is_recoverable_mysql_error() ? ZBX_DB_DOWN : ZBX_DB_FAIL);
1483 				}
1484 			}
1485 			while (0 == status);
1486 		}
1487 	}
1488 #elif defined(HAVE_ORACLE)
1489 	if (OCI_SUCCESS == (err = zbx_oracle_statement_prepare(sql)))
1490 	{
1491 		ub4	nrows = 0;
1492 
1493 		if (OCI_SUCCESS == (err = zbx_oracle_statement_execute(1, &nrows)))
1494 			ret = (int)nrows;
1495 	}
1496 
1497 	if (OCI_SUCCESS != err)
1498 		ret = OCI_handle_sql_error(ERR_Z3005, err, sql);
1499 
1500 #elif defined(HAVE_POSTGRESQL)
1501 	result = PQexec(conn,sql);
1502 
1503 	if (NULL == result)
1504 	{
1505 		zbx_db_errlog(ERR_Z3005, 0, "result is NULL", sql);
1506 		ret = (CONNECTION_OK == PQstatus(conn) ? ZBX_DB_FAIL : ZBX_DB_DOWN);
1507 	}
1508 	else if (PGRES_COMMAND_OK != PQresultStatus(result))
1509 	{
1510 		zbx_postgresql_error(&error, result);
1511 		zbx_db_errlog(ERR_Z3005, 0, error, sql);
1512 		zbx_free(error);
1513 
1514 		ret = (SUCCEED == is_recoverable_postgresql_error(conn, result) ? ZBX_DB_DOWN : ZBX_DB_FAIL);
1515 	}
1516 
1517 	if (ZBX_DB_OK == ret)
1518 		ret = atoi(PQcmdTuples(result));
1519 
1520 	PQclear(result);
1521 #elif defined(HAVE_SQLITE3)
1522 	if (0 == txn_level)
1523 		zbx_mutex_lock(sqlite_access);
1524 
1525 lbl_exec:
1526 	if (SQLITE_OK != (err = sqlite3_exec(conn, sql, NULL, 0, &error)))
1527 	{
1528 		if (SQLITE_BUSY == err)
1529 			goto lbl_exec;
1530 
1531 		zbx_db_errlog(ERR_Z3005, 0, error, sql);
1532 		sqlite3_free(error);
1533 
1534 		switch (err)
1535 		{
1536 			case SQLITE_ERROR:	/* SQL error or missing database; assuming SQL error, because if we
1537 						   are this far into execution, zbx_db_connect() was successful */
1538 			case SQLITE_NOMEM:	/* A malloc() failed */
1539 			case SQLITE_TOOBIG:	/* String or BLOB exceeds size limit */
1540 			case SQLITE_CONSTRAINT:	/* Abort due to constraint violation */
1541 			case SQLITE_MISMATCH:	/* Data type mismatch */
1542 				ret = ZBX_DB_FAIL;
1543 				break;
1544 			default:
1545 				ret = ZBX_DB_DOWN;
1546 				break;
1547 		}
1548 	}
1549 
1550 	if (ZBX_DB_OK == ret)
1551 		ret = sqlite3_changes(conn);
1552 
1553 	if (0 == txn_level)
1554 		zbx_mutex_unlock(sqlite_access);
1555 #endif	/* HAVE_SQLITE3 */
1556 
1557 	if (0 != CONFIG_LOG_SLOW_QUERIES)
1558 	{
1559 		sec = zbx_time() - sec;
1560 		if (sec > (double)CONFIG_LOG_SLOW_QUERIES / 1000.0)
1561 			zabbix_log(LOG_LEVEL_WARNING, "slow query: " ZBX_FS_DBL " sec, \"%s\"", sec, sql);
1562 	}
1563 
1564 	if (ZBX_DB_FAIL == ret && 0 < txn_level)
1565 	{
1566 		zabbix_log(LOG_LEVEL_DEBUG, "query [%s] failed, setting transaction as failed", sql);
1567 		txn_error = ZBX_DB_FAIL;
1568 	}
1569 clean:
1570 	zbx_free(sql);
1571 
1572 	return ret;
1573 }
1574 
1575 /******************************************************************************
1576  *                                                                            *
1577  * Function: zbx_db_vselect                                                   *
1578  *                                                                            *
1579  * Purpose: execute a select statement                                        *
1580  *                                                                            *
1581  * Return value: data, NULL (on error) or (DB_RESULT)ZBX_DB_DOWN              *
1582  *                                                                            *
1583  ******************************************************************************/
zbx_db_vselect(const char * fmt,va_list args)1584 DB_RESULT	zbx_db_vselect(const char *fmt, va_list args)
1585 {
1586 	char		*sql = NULL;
1587 	DB_RESULT	result = NULL;
1588 	double		sec = 0;
1589 #if defined(HAVE_ORACLE)
1590 	sword		err = OCI_SUCCESS;
1591 	ub4		prefetch_rows = 200, counter;
1592 
1593 	ZBX_UNUSED(counter);
1594 #elif defined(HAVE_POSTGRESQL)
1595 	char		*error = NULL;
1596 #elif defined(HAVE_SQLITE3)
1597 	int		ret = FAIL;
1598 	char		*error = NULL;
1599 #endif
1600 
1601 	if (0 != CONFIG_LOG_SLOW_QUERIES)
1602 		sec = zbx_time();
1603 
1604 	sql = zbx_dvsprintf(sql, fmt, args);
1605 
1606 	if (ZBX_DB_OK != txn_error)
1607 	{
1608 		zabbix_log(LOG_LEVEL_DEBUG, "ignoring query [txnlev:%d] [%s] within failed transaction", txn_level, sql);
1609 		goto clean;
1610 	}
1611 
1612 	zabbix_log(LOG_LEVEL_DEBUG, "query [txnlev:%d] [%s]", txn_level, sql);
1613 
1614 #if defined(HAVE_MYSQL)
1615 	result = (DB_RESULT)zbx_malloc(NULL, sizeof(struct zbx_db_result));
1616 	result->result = NULL;
1617 
1618 	if (NULL == conn)
1619 	{
1620 		zbx_db_errlog(ERR_Z3003, 0, NULL, NULL);
1621 
1622 		DBfree_result(result);
1623 		result = NULL;
1624 	}
1625 	else
1626 	{
1627 		if (0 != mysql_query(conn, sql) || NULL == (result->result = mysql_store_result(conn)))
1628 		{
1629 			zbx_db_errlog(ERR_Z3005, mysql_errno(conn), mysql_error(conn), sql);
1630 
1631 			DBfree_result(result);
1632 			result = (SUCCEED == is_recoverable_mysql_error() ? (DB_RESULT)ZBX_DB_DOWN : NULL);
1633 		}
1634 	}
1635 #elif defined(HAVE_ORACLE)
1636 	result = zbx_malloc(NULL, sizeof(struct zbx_db_result));
1637 	memset(result, 0, sizeof(struct zbx_db_result));
1638 	zbx_vector_ptr_append(&oracle.db_results, result);
1639 
1640 	err = OCIHandleAlloc((dvoid *)oracle.envhp, (dvoid **)&result->stmthp, OCI_HTYPE_STMT, (size_t)0, (dvoid **)0);
1641 
1642 	/* Prefetching when working with Oracle is needed because otherwise it fetches only 1 row at a time when doing */
1643 	/* selects (default behavior). There are 2 ways to do prefetching: memory based and rows based. Based on the   */
1644 	/* study optimal (speed-wise) memory based prefetch is 2 MB. But in case of many subsequent selects CPU usage  */
1645 	/* jumps up to 100 %. Using rows prefetch with up to 200 rows does not affect CPU usage, it is the same as     */
1646 	/* without prefetching at all. See ZBX-5920, ZBX-6493 for details.                                             */
1647 	/*                                                                                                             */
1648 	/* Tested on Oracle 11gR2.                                                                                     */
1649 	/*                                                                                                             */
1650 	/* Oracle info: docs.oracle.com/cd/B28359_01/appdev.111/b28395/oci04sql.htm                                    */
1651 
1652 	if (OCI_SUCCESS == err)
1653 	{
1654 		err = OCIAttrSet(result->stmthp, OCI_HTYPE_STMT, &prefetch_rows, sizeof(prefetch_rows),
1655 				OCI_ATTR_PREFETCH_ROWS, oracle.errhp);
1656 	}
1657 
1658 	if (OCI_SUCCESS == err)
1659 	{
1660 		err = OCIStmtPrepare(result->stmthp, oracle.errhp, (text *)sql, (ub4)strlen((char *)sql),
1661 				(ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT);
1662 	}
1663 
1664 	if (OCI_SUCCESS == err)
1665 	{
1666 		err = OCIStmtExecute(oracle.svchp, result->stmthp, oracle.errhp, (ub4)0, (ub4)0,
1667 				(CONST OCISnapshot *)NULL, (OCISnapshot *)NULL,
1668 				0 == txn_level ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT);
1669 	}
1670 
1671 	if (OCI_SUCCESS == err)
1672 	{
1673 		/* get the number of columns in the query */
1674 		err = OCIAttrGet((void *)result->stmthp, OCI_HTYPE_STMT, (void *)&result->ncolumn,
1675 				  (ub4 *)0, OCI_ATTR_PARAM_COUNT, oracle.errhp);
1676 	}
1677 
1678 	if (OCI_SUCCESS != err)
1679 		goto error;
1680 
1681 	assert(0 < result->ncolumn);
1682 
1683 	result->values = zbx_malloc(NULL, result->ncolumn * sizeof(char *));
1684 	result->clobs = zbx_malloc(NULL, result->ncolumn * sizeof(OCILobLocator *));
1685 	result->values_alloc = zbx_malloc(NULL, result->ncolumn * sizeof(ub4));
1686 	memset(result->values, 0, result->ncolumn * sizeof(char *));
1687 	memset(result->clobs, 0, result->ncolumn * sizeof(OCILobLocator *));
1688 	memset(result->values_alloc, 0, result->ncolumn * sizeof(ub4));
1689 
1690 	for (counter = 1; OCI_SUCCESS == err && counter <= (ub4)result->ncolumn; counter++)
1691 	{
1692 		OCIParam	*parmdp = NULL;
1693 		OCIDefine	*defnp = NULL;
1694 		ub4		char_semantics;
1695 		ub2		col_width = 0, data_type = 0;
1696 
1697 		/* request a parameter descriptor in the select-list */
1698 		err = OCIParamGet((void *)result->stmthp, OCI_HTYPE_STMT, oracle.errhp, (void **)&parmdp, (ub4)counter);
1699 
1700 		if (OCI_SUCCESS == err)
1701 		{
1702 			/* retrieve the data type for the column */
1703 			err = OCIAttrGet((void *)parmdp, OCI_DTYPE_PARAM, (dvoid *)&data_type, (ub4 *)NULL,
1704 					(ub4)OCI_ATTR_DATA_TYPE, (OCIError *)oracle.errhp);
1705 		}
1706 
1707 		if (SQLT_CLOB == data_type)
1708 		{
1709 			if (OCI_SUCCESS == err)
1710 			{
1711 				/* allocate the lob locator variable */
1712 				err = OCIDescriptorAlloc((dvoid *)oracle.envhp, (dvoid **)&result->clobs[counter - 1],
1713 						OCI_DTYPE_LOB, (size_t)0, (dvoid **)0);
1714 			}
1715 
1716 			if (OCI_SUCCESS == err)
1717 			{
1718 				/* associate clob var with its define handle */
1719 				err = OCIDefineByPos((void *)result->stmthp, &defnp, (OCIError *)oracle.errhp,
1720 						(ub4)counter, (dvoid *)&result->clobs[counter - 1], (sb4)-1,
1721 						data_type, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT);
1722 			}
1723 		}
1724 		else
1725 		{
1726 			if (SQLT_IBDOUBLE != data_type && SQLT_BDOUBLE != data_type)
1727 			{
1728 				if (OCI_SUCCESS == err)
1729 				{
1730 					/* retrieve the length semantics for the column */
1731 					char_semantics = 0;
1732 					err = OCIAttrGet((void *)parmdp, (ub4)OCI_DTYPE_PARAM, (void *)&char_semantics,
1733 							(ub4 *)NULL, (ub4)OCI_ATTR_CHAR_USED, (OCIError *)oracle.errhp);
1734 				}
1735 
1736 				if (OCI_SUCCESS == err)
1737 				{
1738 					if (0 != char_semantics)
1739 					{
1740 						/* retrieve the column width in characters */
1741 						err = OCIAttrGet((void *)parmdp, (ub4)OCI_DTYPE_PARAM, (void *)&col_width,
1742 								(ub4 *)NULL, (ub4)OCI_ATTR_CHAR_SIZE, (OCIError *)oracle.errhp);
1743 
1744 						/* adjust for UTF-8 */
1745 						col_width *= 4;
1746 					}
1747 					else
1748 					{
1749 						/* retrieve the column width in bytes */
1750 						err = OCIAttrGet((void *)parmdp, (ub4)OCI_DTYPE_PARAM, (void *)&col_width,
1751 								(ub4 *)NULL, (ub4)OCI_ATTR_DATA_SIZE, (OCIError *)oracle.errhp);
1752 					}
1753 				}
1754 				col_width++;	/* add 1 byte for terminating '\0' */
1755 			}
1756 			else
1757 				col_width = ZBX_MAX_DOUBLE_LEN + 1;
1758 
1759 			result->values_alloc[counter - 1] = col_width;
1760 			result->values[counter - 1] = zbx_malloc(NULL, col_width);
1761 			*result->values[counter - 1] = '\0';
1762 
1763 			if (OCI_SUCCESS == err)
1764 			{
1765 				/* represent any data as characters */
1766 				err = OCIDefineByPos(result->stmthp, &defnp, oracle.errhp, counter,
1767 						(dvoid *)result->values[counter - 1], col_width, SQLT_STR,
1768 						(dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT);
1769 			}
1770 		}
1771 
1772 		/* free cell descriptor */
1773 		OCIDescriptorFree(parmdp, OCI_DTYPE_PARAM);
1774 		parmdp = NULL;
1775 	}
1776 error:
1777 	if (OCI_SUCCESS != err)
1778 	{
1779 		int	server_status;
1780 
1781 		server_status = OCI_handle_sql_error(ERR_Z3005, err, sql);
1782 		DBfree_result(result);
1783 
1784 		result = (ZBX_DB_DOWN == server_status ? (DB_RESULT)(intptr_t)server_status : NULL);
1785 	}
1786 #elif defined(HAVE_POSTGRESQL)
1787 	result = zbx_malloc(NULL, sizeof(struct zbx_db_result));
1788 	result->pg_result = PQexec(conn, sql);
1789 	result->values = NULL;
1790 	result->cursor = 0;
1791 	result->row_num = 0;
1792 
1793 	if (NULL == result->pg_result)
1794 		zbx_db_errlog(ERR_Z3005, 0, "result is NULL", sql);
1795 
1796 	if (PGRES_TUPLES_OK != PQresultStatus(result->pg_result))
1797 	{
1798 		zbx_postgresql_error(&error, result->pg_result);
1799 		zbx_db_errlog(ERR_Z3005, 0, error, sql);
1800 		zbx_free(error);
1801 
1802 		if (SUCCEED == is_recoverable_postgresql_error(conn, result->pg_result))
1803 		{
1804 			DBfree_result(result);
1805 			result = (DB_RESULT)ZBX_DB_DOWN;
1806 		}
1807 		else
1808 		{
1809 			DBfree_result(result);
1810 			result = NULL;
1811 		}
1812 	}
1813 	else	/* init rownum */
1814 		result->row_num = PQntuples(result->pg_result);
1815 #elif defined(HAVE_SQLITE3)
1816 	if (0 == txn_level)
1817 		zbx_mutex_lock(sqlite_access);
1818 
1819 	result = zbx_malloc(NULL, sizeof(struct zbx_db_result));
1820 	result->curow = 0;
1821 
1822 lbl_get_table:
1823 	if (SQLITE_OK != (ret = sqlite3_get_table(conn,sql, &result->data, &result->nrow, &result->ncolumn, &error)))
1824 	{
1825 		if (SQLITE_BUSY == ret)
1826 			goto lbl_get_table;
1827 
1828 		zbx_db_errlog(ERR_Z3005, 0, error, sql);
1829 		sqlite3_free(error);
1830 
1831 		DBfree_result(result);
1832 
1833 		switch (ret)
1834 		{
1835 			case SQLITE_ERROR:	/* SQL error or missing database; assuming SQL error, because if we
1836 						   are this far into execution, zbx_db_connect() was successful */
1837 			case SQLITE_NOMEM:	/* a malloc() failed */
1838 			case SQLITE_MISMATCH:	/* data type mismatch */
1839 				result = NULL;
1840 				break;
1841 			default:
1842 				result = (DB_RESULT)ZBX_DB_DOWN;
1843 				break;
1844 		}
1845 	}
1846 
1847 	if (0 == txn_level)
1848 		zbx_mutex_unlock(sqlite_access);
1849 #endif	/* HAVE_SQLITE3 */
1850 	if (0 != CONFIG_LOG_SLOW_QUERIES)
1851 	{
1852 		sec = zbx_time() - sec;
1853 		if (sec > (double)CONFIG_LOG_SLOW_QUERIES / 1000.0)
1854 			zabbix_log(LOG_LEVEL_WARNING, "slow query: " ZBX_FS_DBL " sec, \"%s\"", sec, sql);
1855 	}
1856 
1857 	if (NULL == result && 0 < txn_level)
1858 	{
1859 		zabbix_log(LOG_LEVEL_DEBUG, "query [%s] failed, setting transaction as failed", sql);
1860 		txn_error = ZBX_DB_FAIL;
1861 	}
1862 clean:
1863 	zbx_free(sql);
1864 
1865 	return result;
1866 }
1867 
1868 /*
1869  * Execute SQL statement. For select statements only.
1870  */
zbx_db_select_n(const char * query,int n)1871 DB_RESULT	zbx_db_select_n(const char *query, int n)
1872 {
1873 #if defined(HAVE_ORACLE)
1874 	return zbx_db_select("select * from (%s) where rownum<=%d", query, n);
1875 #elif defined(HAVE_MYSQL) || defined(HAVE_POSTGRESQL) || defined(HAVE_SQLITE3)
1876 	return zbx_db_select("%s limit %d", query, n);
1877 #endif
1878 }
1879 
1880 #ifdef HAVE_POSTGRESQL
1881 /******************************************************************************
1882  *                                                                            *
1883  * Function: zbx_db_bytea_unescape                                            *
1884  *                                                                            *
1885  * Purpose: converts the null terminated string into binary buffer            *
1886  *                                                                            *
1887  * Transformations:                                                           *
1888  *      \ooo == a byte whose value = ooo (ooo is an octal number)             *
1889  *      \\   == \                                                             *
1890  *                                                                            *
1891  * Parameters:                                                                *
1892  *      io - [IN/OUT] null terminated string / binary data                    *
1893  *                                                                            *
1894  * Return value: length of the binary buffer                                  *
1895  *                                                                            *
1896  ******************************************************************************/
zbx_db_bytea_unescape(u_char * io)1897 static size_t	zbx_db_bytea_unescape(u_char *io)
1898 {
1899 	const u_char	*i = io;
1900 	u_char		*o = io;
1901 
1902 	while ('\0' != *i)
1903 	{
1904 		switch (*i)
1905 		{
1906 			case '\\':
1907 				i++;
1908 				if ('\\' == *i)
1909 				{
1910 					*o++ = *i++;
1911 				}
1912 				else
1913 				{
1914 					if (0 != isdigit(i[0]) && 0 != isdigit(i[1]) && 0 != isdigit(i[2]))
1915 					{
1916 						*o = (*i++ - 0x30) << 6;
1917 						*o += (*i++ - 0x30) << 3;
1918 						*o++ += *i++ - 0x30;
1919 					}
1920 				}
1921 				break;
1922 
1923 			default:
1924 				*o++ = *i++;
1925 		}
1926 	}
1927 
1928 	return o - io;
1929 }
1930 #endif
1931 
zbx_db_fetch(DB_RESULT result)1932 DB_ROW	zbx_db_fetch(DB_RESULT result)
1933 {
1934 #if defined(HAVE_ORACLE)
1935 	int		i;
1936 	sword		rc;
1937 	static char	errbuf[512];
1938 	sb4		errcode;
1939 #endif
1940 
1941 	if (NULL == result)
1942 		return NULL;
1943 
1944 #if defined(HAVE_MYSQL)
1945 	if (NULL == result->result)
1946 		return NULL;
1947 
1948 	return (DB_ROW)mysql_fetch_row(result->result);
1949 #elif defined(HAVE_ORACLE)
1950 	if (NULL == result->stmthp)
1951 		return NULL;
1952 
1953 	if (OCI_NO_DATA == (rc = OCIStmtFetch2(result->stmthp, oracle.errhp, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT)))
1954 		return NULL;
1955 
1956 	if (OCI_SUCCESS != rc)
1957 	{
1958 		ub4	rows_fetched;
1959 		ub4	sizep = sizeof(ub4);
1960 
1961 		if (OCI_SUCCESS != (rc = OCIErrorGet((dvoid *)oracle.errhp, (ub4)1, (text *)NULL,
1962 				&errcode, (text *)errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR)))
1963 		{
1964 			zbx_db_errlog(ERR_Z3006, rc, zbx_oci_error(rc, NULL), NULL);
1965 			return NULL;
1966 		}
1967 
1968 		switch (errcode)
1969 		{
1970 			case 1012:	/* ORA-01012: not logged on */
1971 			case 2396:	/* ORA-02396: exceeded maximum idle time */
1972 			case 3113:	/* ORA-03113: end-of-file on communication channel */
1973 			case 3114:	/* ORA-03114: not connected to ORACLE */
1974 				zbx_db_errlog(ERR_Z3006, errcode, errbuf, NULL);
1975 				return NULL;
1976 			default:
1977 				rc = OCIAttrGet((void *)result->stmthp, (ub4)OCI_HTYPE_STMT, (void *)&rows_fetched,
1978 						(ub4 *)&sizep, (ub4)OCI_ATTR_ROWS_FETCHED, (OCIError *)oracle.errhp);
1979 
1980 				if (OCI_SUCCESS != rc || 1 != rows_fetched)
1981 				{
1982 					zbx_db_errlog(ERR_Z3006, errcode, errbuf, NULL);
1983 					return NULL;
1984 				}
1985 		}
1986 	}
1987 
1988 	for (i = 0; i < result->ncolumn; i++)
1989 	{
1990 		ub4	alloc, amount;
1991 		ub1	csfrm;
1992 		sword	rc2;
1993 
1994 		if (NULL == result->clobs[i])
1995 			continue;
1996 
1997 		if (OCI_SUCCESS != (rc2 = OCILobGetLength(oracle.svchp, oracle.errhp, result->clobs[i], &amount)))
1998 		{
1999 			/* If the LOB is NULL, the length is undefined. */
2000 			/* In this case the function returns OCI_INVALID_HANDLE. */
2001 			if (OCI_INVALID_HANDLE != rc2)
2002 			{
2003 				zbx_db_errlog(ERR_Z3006, rc2, zbx_oci_error(rc2, NULL), NULL);
2004 				return NULL;
2005 			}
2006 			else
2007 				amount = 0;
2008 		}
2009 		else if (OCI_SUCCESS != (rc2 = OCILobCharSetForm(oracle.envhp, oracle.errhp, result->clobs[i], &csfrm)))
2010 		{
2011 			zbx_db_errlog(ERR_Z3006, rc2, zbx_oci_error(rc2, NULL), NULL);
2012 			return NULL;
2013 		}
2014 
2015 		if (result->values_alloc[i] < (alloc = amount * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1))
2016 		{
2017 			result->values_alloc[i] = alloc;
2018 			result->values[i] = zbx_realloc(result->values[i], result->values_alloc[i]);
2019 		}
2020 
2021 		if (OCI_SUCCESS == rc2)
2022 		{
2023 			if (OCI_SUCCESS != (rc2 = OCILobRead(oracle.svchp, oracle.errhp, result->clobs[i], &amount,
2024 					(ub4)1, (dvoid *)result->values[i], (ub4)(result->values_alloc[i] - 1),
2025 					(dvoid *)NULL, (OCICallbackLobRead)NULL, (ub2)0, csfrm)))
2026 			{
2027 				zbx_db_errlog(ERR_Z3006, rc2, zbx_oci_error(rc2, NULL), NULL);
2028 				return NULL;
2029 			}
2030 		}
2031 
2032 		result->values[i][amount] = '\0';
2033 	}
2034 
2035 	return result->values;
2036 #elif defined(HAVE_POSTGRESQL)
2037 	/* free old data */
2038 	if (NULL != result->values)
2039 		zbx_free(result->values);
2040 
2041 	/* EOF */
2042 	if (result->cursor == result->row_num)
2043 		return NULL;
2044 
2045 	/* init result */
2046 	result->fld_num = PQnfields(result->pg_result);
2047 
2048 	if (result->fld_num > 0)
2049 	{
2050 		int	i;
2051 
2052 		result->values = zbx_malloc(result->values, sizeof(char *) * result->fld_num);
2053 
2054 		for (i = 0; i < result->fld_num; i++)
2055 		{
2056 			if (PQgetisnull(result->pg_result, result->cursor, i))
2057 			{
2058 				result->values[i] = NULL;
2059 			}
2060 			else
2061 			{
2062 				result->values[i] = PQgetvalue(result->pg_result, result->cursor, i);
2063 				if (PQftype(result->pg_result, i) == ZBX_PG_BYTEAOID)	/* binary data type BYTEAOID */
2064 					zbx_db_bytea_unescape((u_char *)result->values[i]);
2065 			}
2066 		}
2067 	}
2068 
2069 	result->cursor++;
2070 
2071 	return result->values;
2072 #elif defined(HAVE_SQLITE3)
2073 	/* EOF */
2074 	if (result->curow >= result->nrow)
2075 		return NULL;
2076 
2077 	if (NULL == result->data)
2078 		return NULL;
2079 
2080 	result->curow++;	/* NOTE: first row == header row */
2081 
2082 	return &(result->data[result->curow * result->ncolumn]);
2083 #endif
2084 }
2085 
zbx_db_is_null(const char * field)2086 int	zbx_db_is_null(const char *field)
2087 {
2088 	if (NULL == field)
2089 		return SUCCEED;
2090 #ifdef HAVE_ORACLE
2091 	if ('\0' == *field)
2092 		return SUCCEED;
2093 #endif
2094 	return FAIL;
2095 }
2096 
2097 #ifdef HAVE_ORACLE
OCI_DBclean_result(DB_RESULT result)2098 static void	OCI_DBclean_result(DB_RESULT result)
2099 {
2100 	if (NULL == result)
2101 		return;
2102 
2103 	if (NULL != result->values)
2104 	{
2105 		int	i;
2106 
2107 		for (i = 0; i < result->ncolumn; i++)
2108 		{
2109 			zbx_free(result->values[i]);
2110 
2111 			/* deallocate the lob locator variable */
2112 			if (NULL != result->clobs[i])
2113 			{
2114 				OCIDescriptorFree((dvoid *)result->clobs[i], OCI_DTYPE_LOB);
2115 				result->clobs[i] = NULL;
2116 			}
2117 		}
2118 
2119 		zbx_free(result->values);
2120 		zbx_free(result->clobs);
2121 		zbx_free(result->values_alloc);
2122 	}
2123 
2124 	if (result->stmthp)
2125 	{
2126 		OCIHandleFree((dvoid *)result->stmthp, OCI_HTYPE_STMT);
2127 		result->stmthp = NULL;
2128 	}
2129 }
2130 #endif
2131 
DBfree_result(DB_RESULT result)2132 void	DBfree_result(DB_RESULT result)
2133 {
2134 #if defined(HAVE_MYSQL)
2135 	if (NULL == result)
2136 		return;
2137 
2138 	mysql_free_result(result->result);
2139 	zbx_free(result);
2140 #elif defined(HAVE_ORACLE)
2141 	int i;
2142 
2143 	if (NULL == result)
2144 		return;
2145 
2146 	OCI_DBclean_result(result);
2147 
2148 	for (i = 0; i < oracle.db_results.values_num; i++)
2149 	{
2150 		if (oracle.db_results.values[i] == result)
2151 		{
2152 			zbx_vector_ptr_remove_noorder(&oracle.db_results, i);
2153 			break;
2154 		}
2155 	}
2156 
2157 	zbx_free(result);
2158 #elif defined(HAVE_POSTGRESQL)
2159 	if (NULL == result)
2160 		return;
2161 
2162 	if (NULL != result->values)
2163 	{
2164 		result->fld_num = 0;
2165 		zbx_free(result->values);
2166 		result->values = NULL;
2167 	}
2168 
2169 	PQclear(result->pg_result);
2170 	zbx_free(result);
2171 #elif defined(HAVE_SQLITE3)
2172 	if (NULL == result)
2173 		return;
2174 
2175 	if (NULL != result->data)
2176 	{
2177 		sqlite3_free_table(result->data);
2178 	}
2179 
2180 	zbx_free(result);
2181 #endif	/* HAVE_SQLITE3 */
2182 }
2183 
2184 #ifdef HAVE_ORACLE
2185 /* server status: OCI_SERVER_NORMAL or OCI_SERVER_NOT_CONNECTED */
OCI_DBserver_status(void)2186 static ub4	OCI_DBserver_status(void)
2187 {
2188 	sword	err;
2189 	ub4	server_status = OCI_SERVER_NOT_CONNECTED;
2190 
2191 	err = OCIAttrGet((void *)oracle.srvhp, OCI_HTYPE_SERVER, (void *)&server_status,
2192 			(ub4 *)0, OCI_ATTR_SERVER_STATUS, (OCIError *)oracle.errhp);
2193 
2194 	if (OCI_SUCCESS != err)
2195 		zabbix_log(LOG_LEVEL_WARNING, "cannot determine Oracle server status, assuming not connected");
2196 
2197 	return server_status;
2198 }
2199 #endif	/* HAVE_ORACLE */
2200 
zbx_db_is_escape_sequence(char c)2201 static int	zbx_db_is_escape_sequence(char c)
2202 {
2203 #if defined(HAVE_MYSQL)
2204 	if ('\'' == c || '\\' == c)
2205 #elif defined(HAVE_POSTGRESQL)
2206 	if ('\'' == c || ('\\' == c && 1 == ZBX_PG_ESCAPE_BACKSLASH))
2207 #else
2208 	if ('\'' == c)
2209 #endif
2210 		return SUCCEED;
2211 
2212 	return FAIL;
2213 }
2214 
2215 /******************************************************************************
2216  *                                                                            *
2217  * Function: zbx_db_escape_string                                             *
2218  *                                                                            *
2219  * Return value: escaped string                                               *
2220  *                                                                            *
2221  * Comments: sync changes with 'zbx_db_get_escape_string_len'                 *
2222  *           and 'zbx_db_dyn_escape_string'                                   *
2223  *                                                                            *
2224  ******************************************************************************/
zbx_db_escape_string(const char * src,char * dst,size_t len,zbx_escape_sequence_t flag)2225 static void	zbx_db_escape_string(const char *src, char *dst, size_t len, zbx_escape_sequence_t flag)
2226 {
2227 	const char	*s;
2228 	char		*d;
2229 
2230 	assert(dst);
2231 
2232 	len--;	/* '\0' */
2233 
2234 	for (s = src, d = dst; NULL != s && '\0' != *s && 0 < len; s++)
2235 	{
2236 		if (ESCAPE_SEQUENCE_ON == flag && SUCCEED == zbx_db_is_escape_sequence(*s))
2237 		{
2238 			if (2 > len)
2239 				break;
2240 
2241 #if defined(HAVE_MYSQL)
2242 			*d++ = '\\';
2243 #elif defined(HAVE_POSTGRESQL)
2244 			*d++ = *s;
2245 #else
2246 			*d++ = '\'';
2247 #endif
2248 			len--;
2249 		}
2250 		*d++ = *s;
2251 		len--;
2252 	}
2253 	*d = '\0';
2254 }
2255 
2256 /******************************************************************************
2257  *                                                                            *
2258  * Function: zbx_db_get_escape_string_len                                     *
2259  *                                                                            *
2260  * Purpose: to calculate escaped string length limited by bytes or characters *
2261  *          whichever is reached first.                                       *
2262  *                                                                            *
2263  * Parameters: s         - [IN] string to escape                              *
2264  *             max_bytes - [IN] limit in bytes                                *
2265  *             max_chars - [IN] limit in characters                           *
2266  *             flag      - [IN] sequences need to be escaped on/off           *
2267  *                                                                            *
2268  * Return value: return length in bytes of escaped string                     *
2269  *               with terminating '\0'                                        *
2270  *                                                                            *
2271  ******************************************************************************/
zbx_db_get_escape_string_len(const char * s,size_t max_bytes,size_t max_chars,zbx_escape_sequence_t flag)2272 static size_t	zbx_db_get_escape_string_len(const char *s, size_t max_bytes, size_t max_chars,
2273 		zbx_escape_sequence_t flag)
2274 {
2275 	size_t	csize, len = 1;	/* '\0' */
2276 
2277 	if (NULL == s)
2278 		return len;
2279 
2280 	while ('\0' != *s && 0 < max_chars)
2281 	{
2282 		csize = zbx_utf8_char_len(s);
2283 
2284 		/* process non-UTF-8 characters as single byte characters */
2285 		if (0 == csize)
2286 			csize = 1;
2287 
2288 		if (max_bytes < csize)
2289 			break;
2290 
2291 		if (ESCAPE_SEQUENCE_ON == flag && SUCCEED == zbx_db_is_escape_sequence(*s))
2292 			len++;
2293 
2294 		s += csize;
2295 		len += csize;
2296 		max_bytes -= csize;
2297 		max_chars--;
2298 	}
2299 
2300 	return len;
2301 }
2302 
2303 /******************************************************************************
2304  *                                                                            *
2305  * Function: zbx_db_dyn_escape_string                                         *
2306  *                                                                            *
2307  * Purpose: to escape string limited by bytes or characters, whichever limit  *
2308  *          is reached first.                                                 *
2309  *                                                                            *
2310  * Parameters: src       - [IN] string to escape                              *
2311  *             max_bytes - [IN] limit in bytes                                *
2312  *             max_chars - [IN] limit in characters                           *
2313  *             flag      - [IN] sequences need to be escaped on/off           *
2314  *                                                                            *
2315  * Return value: escaped string                                               *
2316  *                                                                            *
2317  ******************************************************************************/
zbx_db_dyn_escape_string(const char * src,size_t max_bytes,size_t max_chars,zbx_escape_sequence_t flag)2318 char	*zbx_db_dyn_escape_string(const char *src, size_t max_bytes, size_t max_chars, zbx_escape_sequence_t flag)
2319 {
2320 	char	*dst = NULL;
2321 	size_t	len;
2322 
2323 	len = zbx_db_get_escape_string_len(src, max_bytes, max_chars, flag);
2324 
2325 	dst = (char *)zbx_malloc(dst, len);
2326 
2327 	zbx_db_escape_string(src, dst, len, flag);
2328 
2329 	return dst;
2330 }
2331 
2332 /******************************************************************************
2333  *                                                                            *
2334  * Function: zbx_db_get_escape_like_pattern_len                               *
2335  *                                                                            *
2336  * Return value: return length of escaped LIKE pattern with terminating '\0'  *
2337  *                                                                            *
2338  * Comments: sync changes with 'zbx_db_escape_like_pattern'                   *
2339  *                                                                            *
2340  ******************************************************************************/
zbx_db_get_escape_like_pattern_len(const char * src)2341 static int	zbx_db_get_escape_like_pattern_len(const char *src)
2342 {
2343 	int		len;
2344 	const char	*s;
2345 
2346 	len = zbx_db_get_escape_string_len(src, ZBX_SIZE_T_MAX, ZBX_SIZE_T_MAX, ESCAPE_SEQUENCE_ON) - 1; /* minus '\0' */
2347 
2348 	for (s = src; s && *s; s++)
2349 	{
2350 		len += (*s == '_' || *s == '%' || *s == ZBX_SQL_LIKE_ESCAPE_CHAR);
2351 		len += 1;
2352 	}
2353 
2354 	len++; /* '\0' */
2355 
2356 	return len;
2357 }
2358 
2359 /******************************************************************************
2360  *                                                                            *
2361  * Function: zbx_db_escape_like_pattern                                       *
2362  *                                                                            *
2363  * Return value: escaped string to be used as pattern in LIKE                 *
2364  *                                                                            *
2365  * Comments: sync changes with 'zbx_db_get_escape_like_pattern_len'           *
2366  *                                                                            *
2367  *           For instance, we wish to find string a_b%c\d'e!f in our database *
2368  *           using '!' as escape character. Our queries then become:          *
2369  *                                                                            *
2370  *           ... LIKE 'a!_b!%c\\d\'e!!f' ESCAPE '!' (MySQL, PostgreSQL)       *
2371  *           ... LIKE 'a!_b!%c\d''e!!f' ESCAPE '!' (Oracle, SQLite3)          *
2372  *                                                                            *
2373  *           Using backslash as escape character in LIKE would be too much    *
2374  *           trouble, because escaping backslashes would have to be escaped   *
2375  *           as well, like so:                                                *
2376  *                                                                            *
2377  *           ... LIKE 'a\\_b\\%c\\\\d\'e!f' ESCAPE '\\' or                    *
2378  *           ... LIKE 'a\\_b\\%c\\\\d\\\'e!f' ESCAPE '\\' (MySQL, PostgreSQL) *
2379  *           ... LIKE 'a\_b\%c\\d''e!f' ESCAPE '\' (Oracle, SQLite3)          *
2380  *                                                                            *
2381  *           Hence '!' instead of backslash.                                  *
2382  *                                                                            *
2383  ******************************************************************************/
zbx_db_escape_like_pattern(const char * src,char * dst,int len)2384 static void	zbx_db_escape_like_pattern(const char *src, char *dst, int len)
2385 {
2386 	char		*d;
2387 	char		*tmp = NULL;
2388 	const char	*t;
2389 
2390 	assert(dst);
2391 
2392 	tmp = (char *)zbx_malloc(tmp, len);
2393 
2394 	zbx_db_escape_string(src, tmp, len, ESCAPE_SEQUENCE_ON);
2395 
2396 	len--; /* '\0' */
2397 
2398 	for (t = tmp, d = dst; t && *t && len; t++)
2399 	{
2400 		if (*t == '_' || *t == '%' || *t == ZBX_SQL_LIKE_ESCAPE_CHAR)
2401 		{
2402 			if (len <= 1)
2403 				break;
2404 			*d++ = ZBX_SQL_LIKE_ESCAPE_CHAR;
2405 			len--;
2406 		}
2407 		*d++ = *t;
2408 		len--;
2409 	}
2410 
2411 	*d = '\0';
2412 
2413 	zbx_free(tmp);
2414 }
2415 
2416 /******************************************************************************
2417  *                                                                            *
2418  * Function: zbx_db_dyn_escape_like_pattern                                   *
2419  *                                                                            *
2420  * Return value: escaped string to be used as pattern in LIKE                 *
2421  *                                                                            *
2422  ******************************************************************************/
zbx_db_dyn_escape_like_pattern(const char * src)2423 char	*zbx_db_dyn_escape_like_pattern(const char *src)
2424 {
2425 	int	len;
2426 	char	*dst = NULL;
2427 
2428 	len = zbx_db_get_escape_like_pattern_len(src);
2429 
2430 	dst = (char *)zbx_malloc(dst, len);
2431 
2432 	zbx_db_escape_like_pattern(src, dst, len);
2433 
2434 	return dst;
2435 }
2436 
2437 /******************************************************************************
2438  *                                                                            *
2439  * Function: zbx_db_strlen_n                                                  *
2440  *                                                                            *
2441  * Purpose: return the string length to fit into a database field of the      *
2442  *          specified size                                                    *
2443  *                                                                            *
2444  * Return value: the string length in bytes                                   *
2445  *                                                                            *
2446  ******************************************************************************/
zbx_db_strlen_n(const char * text_loc,size_t maxlen)2447 int	zbx_db_strlen_n(const char *text_loc, size_t maxlen)
2448 {
2449 	return zbx_strlen_utf8_nchars(text_loc, maxlen);
2450 }
2451 
2452 /******************************************************************************
2453  *                                                                            *
2454  * Function: zbx_db_version_check                                             *
2455  *                                                                            *
2456  * Purpose: determine if a vendor database(MySQL, MariaDB, PostgreSQL,        *
2457  *          Oracle, ElasticDB) version satisfies Zabbix requirements          *
2458  *                                                                            *
2459  * Parameters: database         - [IN] database name                          *
2460  *             current_version  - [IN] detected numeric version               *
2461  *             min_version      - [IN] minimum required numeric version       *
2462  *             max_version      - [IN] maximum required numeric version       *
2463  *                                                                            *
2464  * Return value: resulting status flag                                        *
2465  *                                                                            *
2466  ******************************************************************************/
zbx_db_version_check(const char * database,zbx_uint32_t current_version,zbx_uint32_t min_version,zbx_uint32_t max_version)2467 int	zbx_db_version_check(const char *database, zbx_uint32_t current_version, zbx_uint32_t min_version,
2468 		zbx_uint32_t max_version)
2469 {
2470 	int	flag;
2471 
2472 	if (ZBX_DBVERSION_UNDEFINED == current_version)
2473 	{
2474 		flag = DB_VERSION_FAILED_TO_RETRIEVE;
2475 		zabbix_log(LOG_LEVEL_WARNING, "Failed to retrieve %s version", database);
2476 	}
2477 	else if (min_version > current_version && ZBX_DBVERSION_UNDEFINED != min_version)
2478 	{
2479 		flag = DB_VERSION_LOWER_THAN_MINIMUM;
2480 		zabbix_log(LOG_LEVEL_WARNING, "Unsupported DB! %s version is %lu which is smaller than minimum of %lu",
2481 				database, (unsigned long)current_version, (unsigned long)min_version);
2482 	}
2483 	else if (max_version < current_version && ZBX_DBVERSION_UNDEFINED != max_version)
2484 	{
2485 		flag = DB_VERSION_HIGHER_THAN_MAXIMUM;
2486 		zabbix_log(LOG_LEVEL_WARNING, "Unsupported DB! %s version is %lu which is higher than maximum of %lu",
2487 				database, (unsigned long)current_version, (unsigned long)max_version);
2488 	}
2489 	else
2490 		flag = DB_VERSION_SUPPORTED;
2491 
2492 	return flag;
2493 }
2494 
2495 /******************************************************************************
2496  *                                                                            *
2497  * Function: zbx_db_version_json_create                                       *
2498  *                                                                            *
2499  * Purpose: prepare json for front-end with the DB current, minimum and       *
2500  *          maximum versions and a flag that indicates if the version         *
2501  *          satisfies the requirements                                        *
2502  *                                                                            *
2503  * Parameters:  json                     - [IN/OUT] json data                 *
2504  *              database                 - [IN] name of DB (MySQL/ElasticDB)  *
2505  *              friendly_current_version - [IN] string current version        *
2506  *              friendly_min_version     - [IN] string min version            *
2507  *              friendly_max_version     - [IN] string max version            *
2508  *              flag                     - [IN] status if DB satisfies the    *
2509  *                                         requirements                       *
2510  *                                                                            *
2511  ******************************************************************************/
zbx_db_version_json_create(struct zbx_json * json,const char * database,const char * friendly_current_version,const char * friendly_min_version,const char * friendly_max_version,int flag)2512 void	zbx_db_version_json_create(struct zbx_json *json, const char *database, const char *friendly_current_version,
2513 		const char *friendly_min_version, const char *friendly_max_version, int flag)
2514 {
2515 	zbx_json_addobject(json, NULL);
2516 	zbx_json_addstring(json, "database", database, ZBX_JSON_TYPE_STRING);
2517 
2518 	if (DB_VERSION_FAILED_TO_RETRIEVE != flag)
2519 		zbx_json_addstring(json, "current_version", friendly_current_version, ZBX_JSON_TYPE_STRING);
2520 
2521 	zbx_json_addstring(json, "min_version", friendly_min_version, ZBX_JSON_TYPE_STRING);
2522 	zbx_json_addstring(json, "max_version", friendly_max_version, ZBX_JSON_TYPE_STRING);
2523 	zbx_json_addint64(json, "flag", flag);
2524 	zbx_json_close(json);
2525 }
2526 
2527 /******************************************************************************
2528  *                                                                            *
2529  * Function: zbx_dbms_version_get                                             *
2530  *                                                                            *
2531  * Purpose: For PostgreSQL, MySQL and MariaDB:                                *
2532  *          returns DBMS version as integer: MMmmuu                           *
2533  *          M = major version part                                            *
2534  *          m = minor version part                                            *
2535  *          u = patch version part                                            *
2536  *                                                                            *
2537  * Example: if the original DB version was 1.2.34 then 10234 gets returned    *
2538  *                                                                            *
2539  * Purpose: For OracleDB:                                                      *
2540  *          returns DBMS version as integer: MRruRRivUU                       *
2541  *          MR = major release version part                                   *
2542  *          ru = release update version part                                  *
2543  *          RR = release update version revision part                         *
2544  *          iv = increment version part                                       *
2545  *          UU = unused, reserved for future use                              *
2546  *                                                                            *
2547  * Example: if the OracleDB version was 18.1.0.0.7 then 1801000007 gets       *
2548  *          returned                                                          *
2549  *                                                                            *
2550  * Return value: DBMS version or DBVERSION_UNDEFINED if unknown               *
2551  *                                                                            *
2552  ******************************************************************************/
zbx_dbms_version_get(void)2553 zbx_uint32_t	zbx_dbms_version_get(void)
2554 {
2555 #if defined(HAVE_MYSQL)
2556 	return ZBX_MYSQL_SVERSION;
2557 #elif defined(HAVE_POSTGRESQL)
2558 	return ZBX_PG_SVERSION;
2559 #elif defined(HAVE_ORACLE)
2560 	return ZBX_ORACLE_SVERSION;
2561 #else
2562 	return ZBX_DBVERSION_UNDEFINED;
2563 #endif
2564 }
2565 
2566 #ifdef HAVE_MYSQL
2567 /******************************************************************************
2568  *                                                                            *
2569  * Function: zbx_dbms_mariadb_used                                            *
2570  *                                                                            *
2571  * Purpose: returns flag if the mariadb was detected                          *
2572  *                                                                            *
2573  * Return value: ON  - mariadb detected                                       *
2574  *               OFF - otherwise (it is unforked mysql)                       *
2575  ******************************************************************************/
zbx_dbms_mariadb_used(void)2576 int	zbx_dbms_mariadb_used(void)
2577 {
2578 	return ZBX_MARIADB_SFORK;
2579 }
2580 #endif
2581 
2582 /***************************************************************************************************************
2583  *                                                                                                             *
2584  * Function: zbx_dbms_version_extract                                                                          *
2585  *                                                                                                             *
2586  * Purpose: retrieves the DB version and makes sure it is stored in the numeric format, also fills the json    *
2587  *          to report to front-end                                                                             *
2588  *                                                                                                             *
2589  *          For PostgreSQL:                                                                                    *
2590  *          numeric version is available from the API                                                          *
2591  *                                                                                                             *
2592  *          For MySQL and MariaDB:                                                                             *
2593  *          numeric version is available from the API, but also the additional processing is required          *
2594  *          to determine if it is a MySQL or MariaDB and save this result as well                              *
2595  *                                                                                                             *
2596  *          For Oracle:                                                                                        *
2597  *          numeric version needs to be manually parsed from the string result                                 *
2598  *          Oracle DB format is like 18.1.2.3.0 where                                                          *
2599  *            18 - major release version                                                                       *
2600  *            1 - release update version                                                                       *
2601  *            2 - release update version revision                                                              *
2602  *            3 - increment version                                                                            *
2603  *            0 - unused, reserved for future use                                                              *
2604  *                                                                                                             *
2605  *          Oracle Examples:                                                                                   *
2606  *          For "Oracle Database 18c Express Edition Release 1.0.0.0.0 - Production"    => 100000000           *
2607  *          For "Oracle Database 18c Express Edition Release 18.2.0.0.7 - Production"   => 1802000007          *
2608  *          For "Oracle Database 18c Express Edition Release 0.0.34.123.7 - Production" => DBVERSION_UNDEFINED *
2609  *          For "Oracle Database 18c Express Edition Release 1.0.3.x.7 - Production"    => DBVERISON_UNDEFINED *
2610  *          For "<anything else>"                                                       => DBVERSION_UNDEFINED *
2611  *                                                                                                             *
2612  **************************************************************************************************************/
zbx_dbms_version_extract(struct zbx_json * json)2613 zbx_uint32_t	zbx_dbms_version_extract(struct zbx_json *json)
2614 {
2615 #define RIGHT2(x)	((int)((zbx_uint32_t)(x) - ((zbx_uint32_t)((x)/100))*100))
2616 #if defined(HAVE_MYSQL)
2617 	int		flag, client_major_version, client_minor_version, client_release_version, server_major_version,
2618 			server_minor_version, server_release_version;
2619 	const char	*info;
2620 	char		*version_friendly;
2621 
2622 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2623 
2624 	if (NULL != (info = mysql_get_server_info(conn)) && NULL != strstr(info, "MariaDB"))
2625 	{
2626 		zabbix_log(LOG_LEVEL_DEBUG, "MariaDB fork detected");
2627 		ZBX_MARIADB_SFORK = ON;
2628 	}
2629 
2630 	if (ON == ZBX_MARIADB_SFORK && 6 == sscanf(info, "%d.%d.%d-%d.%d.%d-MariaDB", &client_major_version,
2631 			&client_minor_version, &client_release_version, &server_major_version,
2632 			&server_minor_version, &server_release_version))
2633 	{
2634 		ZBX_MYSQL_SVERSION = server_major_version * 10000 + server_minor_version * 100 +
2635 				server_release_version;
2636 		zabbix_log(LOG_LEVEL_DEBUG, "MariaDB subversion detected");
2637 	}
2638 	else
2639 		ZBX_MYSQL_SVERSION = (zbx_uint32_t)mysql_get_server_version(conn);
2640 
2641 	version_friendly = zbx_dsprintf(NULL, "%d.%.2d.%.2d", RIGHT2(ZBX_MYSQL_SVERSION/10000),
2642 			RIGHT2(ZBX_MYSQL_SVERSION/100), RIGHT2(ZBX_MYSQL_SVERSION));
2643 
2644 	if (ON == ZBX_MARIADB_SFORK)
2645 	{
2646 		flag = zbx_db_version_check("MariaDB",  ZBX_MYSQL_SVERSION, ZBX_MARIA_MIN_VERSION, ZBX_DBVERSION_UNDEFINED);
2647 		zbx_db_version_json_create(json, "MariaDB", version_friendly,
2648 				ZBX_MARIA_MIN_VERSION_FRIENDLY, ZBX_MARIA_MAX_VERSION_FRIENDLY, flag);
2649 	}
2650 	else
2651 	{
2652 		flag = zbx_db_version_check("MySQL", ZBX_MYSQL_SVERSION, ZBX_MYSQL_MIN_VERSION, ZBX_MYSQL_MAX_VERSION);
2653 		zbx_db_version_json_create(json, "MySQL", version_friendly,
2654 				ZBX_MYSQL_MIN_VERSION_FRIENDLY, ZBX_MYSQL_MAX_VERSION_FRIENDLY, flag);
2655 	}
2656 
2657 	zbx_free(version_friendly);
2658 #elif defined(HAVE_POSTGRESQL)
2659 	int		flag;
2660 	char		*version_friendly;
2661 	zbx_uint32_t	major;
2662 
2663 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2664 	ZBX_PG_SVERSION = PQserverVersion(conn);
2665 	major = RIGHT2(ZBX_PG_SVERSION/10000);
2666 
2667 	if (10 > major)
2668 	{
2669 		version_friendly = zbx_dsprintf(NULL, "%d.%d.%d", major, RIGHT2(ZBX_PG_SVERSION/100),
2670 				RIGHT2(ZBX_PG_SVERSION));
2671 	}
2672 	else
2673 	{
2674 		version_friendly = zbx_dsprintf(NULL, "%d.%d", major, RIGHT2(ZBX_PG_SVERSION));
2675 	}
2676 
2677 	flag = zbx_db_version_check("PostgreSQL", ZBX_PG_SVERSION, ZBX_POSTGRESQL_MIN_VERSION,
2678 			ZBX_POSTGRESQL_MAX_VERSION);
2679 	zbx_db_version_json_create(json, "PostgreSQL", version_friendly,
2680 			ZBX_POSTGRESQL_MIN_VERSION_FRIENDLY, ZBX_POSTGRESQL_MAX_VERSION_FRIENDLY, flag);
2681 	zbx_free(version_friendly);
2682 #elif defined(HAVE_ORACLE)
2683 #	ifdef HAVE_OCI_SERVER_RELEASE2
2684 	char	*version_str = "Version ";
2685 	ub4	oci_ver = 0;
2686 #	endif
2687 	char	*start, *release_str = "Release ";
2688 	char	version_friendly[MAX_STRING_LEN / 8];
2689 	int	flag, major_release_version, release_update_version, release_update_version_revision,
2690 			increment_version, reserved_for_future_use, overall_status = SUCCEED;
2691 
2692 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2693 #	ifdef HAVE_OCI_SERVER_RELEASE2
2694 	if (OCI_SUCCESS != OCIServerRelease2(oracle.svchp, oracle.errhp, (OraText *) version_friendly,
2695 			(ub4)sizeof(version_friendly), OCI_HTYPE_SVCCTX, &oci_ver, OCI_DEFAULT))
2696 #	else
2697 	if (OCI_SUCCESS != OCIServerVersion(oracle.svchp, oracle.errhp, (OraText *) version_friendly,
2698 			(ub4)sizeof(version_friendly), OCI_HTYPE_SVCCTX))
2699 #	endif
2700 	{
2701 		overall_status = FAIL;
2702 		goto out;
2703 	}
2704 
2705 	zabbix_log(LOG_LEVEL_DEBUG, "OracleDB version retrieved unparsed: %s", version_friendly);
2706 
2707 	if (
2708 #	ifdef HAVE_OCI_SERVER_RELEASE2
2709 			NULL != (start = strstr(version_friendly, version_str)) ||
2710 #	endif
2711 			NULL != (start = strstr(version_friendly, release_str)))
2712 	{
2713 		size_t	next_start_index;
2714 
2715 		next_start_index = start - version_friendly + strlen(release_str); /* same length for version_str */
2716 
2717 		if (5 != sscanf(version_friendly + next_start_index, "%d.%d.%d.%d.%d", &major_release_version,
2718 				&release_update_version, &release_update_version_revision, &increment_version,
2719 				&reserved_for_future_use) || major_release_version >= 100 ||
2720 				major_release_version <= 0 || release_update_version >= 100 ||
2721 				release_update_version < 0 || release_update_version_revision >= 100 ||
2722 				release_update_version_revision < 0 || increment_version >= 100 ||
2723 				increment_version < 0)
2724 		{
2725 			zabbix_log(LOG_LEVEL_WARNING, "Unexpected Oracle DB version format: %s", version_friendly);
2726 			overall_status = FAIL;
2727 		}
2728 	}
2729 	else
2730 	{
2731 		zabbix_log(LOG_LEVEL_WARNING, "Cannot find Release keyword in Oracle DB version.");
2732 		overall_status = FAIL;
2733 	}
2734 out:
2735 	if (FAIL == overall_status)
2736 	{
2737 		zabbix_log(LOG_LEVEL_WARNING, "Failed to detect OracleDB version");
2738 		ZBX_ORACLE_SVERSION = ZBX_DBVERSION_UNDEFINED;
2739 	}
2740 	else
2741 	{
2742 		ZBX_ORACLE_SVERSION = major_release_version * 100000000 + release_update_version * 1000000 +
2743 				release_update_version_revision * 10000 + increment_version * 100 +
2744 				reserved_for_future_use;
2745 #	ifndef HAVE_OCI_SERVER_RELEASE2
2746 		if (18 <= major_release_version)
2747 		{
2748 			zabbix_log(LOG_LEVEL_WARNING, "Unable to determine the accurate Oracle DB version "
2749 					"(possibly there is a DB driver - DB version mismatch, "
2750 					"only the major Oracle DB version can be established): %s", version_friendly);
2751 		}
2752 #	endif
2753 	}
2754 
2755 	flag = zbx_db_version_check("Oracle", ZBX_ORACLE_SVERSION, ZBX_ORACLE_MIN_VERSION, ZBX_ORACLE_MAX_VERSION);
2756 	zbx_db_version_json_create(json, "Oracle", version_friendly, ZBX_ORACLE_MIN_VERSION_FRIENDLY,
2757 			ZBX_ORACLE_MAX_VERSION_FRIENDLY, flag);
2758 #else
2759 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2760 #endif
2761 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() version:%lu", __func__, (unsigned long)zbx_dbms_version_get());
2762 
2763 	return zbx_dbms_version_get();
2764 }
2765 
2766 #if defined(HAVE_POSTGRESQL)
2767 /******************************************************************************
2768  *                                                                            *
2769  * Function: zbx_tsdb_get_version                                             *
2770  *                                                                            *
2771  * Purpose: returns TimescaleDB (TSDB) version as integer: MMmmuu             *
2772  *          M = major version part                                            *
2773  *          m = minor version part                                            *
2774  *          u = patch version part                                            *
2775  *                                                                            *
2776  * Example: TSDB 1.5.1 version will be returned as 10501                      *
2777  *                                                                            *
2778  * Return value: TSDB version or 0 if unknown or the extension not installed  *
2779  *                                                                            *
2780  ******************************************************************************/
zbx_tsdb_get_version(void)2781 int	zbx_tsdb_get_version(void)
2782 {
2783 	int		ver, major, minor, patch;
2784 	DB_RESULT	result;
2785 	DB_ROW		row;
2786 
2787 	if (-1 == ZBX_TSDB_VERSION)
2788 	{
2789 		/* catalog pg_extension not available */
2790 		if (90001 > ZBX_PG_SVERSION)
2791 		{
2792 			ver = ZBX_TSDB_VERSION = 0;
2793 			goto out;
2794 		}
2795 
2796 		result = zbx_db_select("select extversion from pg_extension where extname = 'timescaledb'");
2797 
2798 		/* database down, can re-query in the next call */
2799 		if ((DB_RESULT)ZBX_DB_DOWN == result)
2800 		{
2801 			ver = 0;
2802 			goto out;
2803 		}
2804 
2805 		/* extension is not installed */
2806 		if (NULL == result)
2807 		{
2808 			ver = ZBX_TSDB_VERSION = 0;
2809 			goto out;
2810 		}
2811 
2812 		if (NULL != (row = zbx_db_fetch(result)) &&
2813 				3 == sscanf((const char*)row[0], "%d.%d.%d", &major, &minor, &patch))
2814 		{
2815 			ver = major * 10000;
2816 			ver += minor * 100;
2817 			ver += patch;
2818 			ZBX_TSDB_VERSION = ver;
2819 		}
2820 		else
2821 			ver = ZBX_TSDB_VERSION = 0;
2822 
2823 		DBfree_result(result);
2824 	}
2825 	else
2826 		ver = ZBX_TSDB_VERSION;
2827 out:
2828 	return ver;
2829 }
2830 
2831 #endif
2832