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