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