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 "db.h"
21 #include "log.h"
22 #include "common.h"
23 #include "events.h"
24 #include "threads.h"
25 #include "zbxserver.h"
26 #include "dbcache.h"
27 #include "zbxalgo.h"
28 
29 #if defined(HAVE_MYSQL) || defined(HAVE_ORACLE) || defined(HAVE_POSTGRESQL)
30 #define ZBX_SUPPORTED_DB_CHARACTER_SET	"utf8"
31 #endif
32 #if defined(HAVE_MYSQL)
33 #define ZBX_SUPPORTED_DB_COLLATION	"utf8_bin"
34 #endif
35 
36 typedef struct
37 {
38 	zbx_uint64_t	autoreg_hostid;
39 	zbx_uint64_t	hostid;
40 	char		*host;
41 	char		*ip;
42 	char		*dns;
43 	char		*host_metadata;
44 	int		now;
45 	unsigned short	port;
46 }
47 zbx_autoreg_host_t;
48 
49 #if defined(HAVE_POSTGRESQL)
50 extern char	ZBX_PG_ESCAPE_BACKSLASH;
51 #endif
52 
53 static int	connection_failure;
54 
DBclose(void)55 void	DBclose(void)
56 {
57 	zbx_db_close();
58 }
59 
60 /******************************************************************************
61  *                                                                            *
62  * Function: DBinit_autoincrement_options                                     *
63  *                                                                            *
64  * Purpose: specify the autoincrement options when connecting to the database *
65  *                                                                            *
66  ******************************************************************************/
DBinit_autoincrement_options(void)67 void	DBinit_autoincrement_options(void)
68 {
69 	zbx_db_init_autoincrement_options();
70 }
71 
72 /******************************************************************************
73  *                                                                            *
74  * Function: DBconnect                                                        *
75  *                                                                            *
76  * Purpose: connect to the database                                           *
77  *                                                                            *
78  * Parameters: flag - ZBX_DB_CONNECT_ONCE (try once and return the result),   *
79  *                    ZBX_DB_CONNECT_EXIT (exit on failure) or                *
80  *                    ZBX_DB_CONNECT_NORMAL (retry until connected)           *
81  *                                                                            *
82  * Return value: same as zbx_db_connect()                                     *
83  *                                                                            *
84  ******************************************************************************/
DBconnect(int flag)85 int	DBconnect(int flag)
86 {
87 	const char	*__function_name = "DBconnect";
88 
89 	int		err;
90 
91 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() flag:%d", __function_name, flag);
92 
93 	while (ZBX_DB_OK != (err = zbx_db_connect(CONFIG_DBHOST, CONFIG_DBUSER, CONFIG_DBPASSWORD,
94 			CONFIG_DBNAME, CONFIG_DBSCHEMA, CONFIG_DBSOCKET, CONFIG_DBPORT)))
95 	{
96 		if (ZBX_DB_CONNECT_ONCE == flag)
97 			break;
98 
99 		if (ZBX_DB_FAIL == err || ZBX_DB_CONNECT_EXIT == flag)
100 		{
101 			zabbix_log(LOG_LEVEL_CRIT, "Cannot connect to the database. Exiting...");
102 			exit(EXIT_FAILURE);
103 		}
104 
105 		zabbix_log(LOG_LEVEL_ERR, "database is down: reconnecting in %d seconds", ZBX_DB_WAIT_DOWN);
106 		connection_failure = 1;
107 		zbx_sleep(ZBX_DB_WAIT_DOWN);
108 	}
109 
110 	if (0 != connection_failure)
111 	{
112 		zabbix_log(LOG_LEVEL_ERR, "database connection re-established");
113 		connection_failure = 0;
114 	}
115 
116 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, err);
117 
118 	return err;
119 }
120 
121 /******************************************************************************
122  *                                                                            *
123  * Function: DBinit                                                           *
124  *                                                                            *
125  * Author: Alexander Vladishev                                                *
126  *                                                                            *
127  ******************************************************************************/
DBinit(char ** error)128 int	DBinit(char **error)
129 {
130 	return zbx_db_init(CONFIG_DBNAME, db_schema, error);
131 }
132 
DBdeinit(void)133 void	DBdeinit(void)
134 {
135 	zbx_db_deinit();
136 }
137 
138 /******************************************************************************
139  *                                                                            *
140  * Function: DBtxn_operation                                                  *
141  *                                                                            *
142  * Purpose: helper function to loop transaction operation while DB is down    *
143  *                                                                            *
144  * Author: Eugene Grigorjev, Vladimir Levijev                                 *
145  *                                                                            *
146  ******************************************************************************/
DBtxn_operation(int (* txn_operation)(void))147 static void	DBtxn_operation(int (*txn_operation)(void))
148 {
149 	int	rc;
150 
151 	rc = txn_operation();
152 
153 	while (ZBX_DB_DOWN == rc)
154 	{
155 		DBclose();
156 		DBconnect(ZBX_DB_CONNECT_NORMAL);
157 
158 		if (ZBX_DB_DOWN == (rc = txn_operation()))
159 		{
160 			zabbix_log(LOG_LEVEL_ERR, "database is down: retrying in %d seconds", ZBX_DB_WAIT_DOWN);
161 			connection_failure = 1;
162 			sleep(ZBX_DB_WAIT_DOWN);
163 		}
164 	}
165 }
166 
167 /******************************************************************************
168  *                                                                            *
169  * Function: DBbegin                                                          *
170  *                                                                            *
171  * Purpose: start a transaction                                               *
172  *                                                                            *
173  * Author: Eugene Grigorjev, Vladimir Levijev                                 *
174  *                                                                            *
175  * Comments: do nothing if DB does not support transactions                   *
176  *                                                                            *
177  ******************************************************************************/
DBbegin(void)178 void	DBbegin(void)
179 {
180 	DBtxn_operation(zbx_db_begin);
181 }
182 
183 /******************************************************************************
184  *                                                                            *
185  * Function: DBcommit                                                         *
186  *                                                                            *
187  * Purpose: commit a transaction                                              *
188  *                                                                            *
189  * Author: Eugene Grigorjev, Vladimir Levijev                                 *
190  *                                                                            *
191  * Comments: do nothing if DB does not support transactions                   *
192  *                                                                            *
193  ******************************************************************************/
DBcommit(void)194 int	DBcommit(void)
195 {
196 	if (ZBX_DB_OK > zbx_db_commit())
197 	{
198 		zabbix_log(LOG_LEVEL_DEBUG, "commit called on failed transaction, doing a rollback instead");
199 		DBrollback();
200 	}
201 
202 	return zbx_db_txn_end_error();
203 }
204 
205 /******************************************************************************
206  *                                                                            *
207  * Function: DBrollback                                                       *
208  *                                                                            *
209  * Purpose: rollback a transaction                                            *
210  *                                                                            *
211  * Author: Eugene Grigorjev, Vladimir Levijev                                 *
212  *                                                                            *
213  * Comments: do nothing if DB does not support transactions                   *
214  *                                                                            *
215  ******************************************************************************/
DBrollback(void)216 void	DBrollback(void)
217 {
218 	if (ZBX_DB_OK > zbx_db_rollback())
219 	{
220 		zabbix_log(LOG_LEVEL_WARNING, "cannot perform transaction rollback, connection will be reset");
221 
222 		DBclose();
223 		DBconnect(ZBX_DB_CONNECT_NORMAL);
224 	}
225 }
226 
227 /******************************************************************************
228  *                                                                            *
229  * Function: DBend                                                            *
230  *                                                                            *
231  * Purpose: commit or rollback a transaction depending on a parameter value   *
232  *                                                                            *
233  * Comments: do nothing if DB does not support transactions                   *
234  *                                                                            *
235  ******************************************************************************/
DBend(int ret)236 int	DBend(int ret)
237 {
238 	if (SUCCEED == ret)
239 		return ZBX_DB_OK == DBcommit() ? SUCCEED : FAIL;
240 
241 	DBrollback();
242 
243 	return FAIL;
244 }
245 
246 #ifdef HAVE_ORACLE
247 /******************************************************************************
248  *                                                                            *
249  * Function: DBstatement_prepare                                              *
250  *                                                                            *
251  * Purpose: prepares a SQL statement for execution                            *
252  *                                                                            *
253  * Comments: retry until DB is up                                             *
254  *                                                                            *
255  ******************************************************************************/
DBstatement_prepare(const char * sql)256 void	DBstatement_prepare(const char *sql)
257 {
258 	int	rc;
259 
260 	rc = zbx_db_statement_prepare(sql);
261 
262 	while (ZBX_DB_DOWN == rc)
263 	{
264 		DBclose();
265 		DBconnect(ZBX_DB_CONNECT_NORMAL);
266 
267 		if (ZBX_DB_DOWN == (rc = zbx_db_statement_prepare(sql)))
268 		{
269 			zabbix_log(LOG_LEVEL_ERR, "database is down: retrying in %d seconds", ZBX_DB_WAIT_DOWN);
270 			connection_failure = 1;
271 			sleep(ZBX_DB_WAIT_DOWN);
272 		}
273 	}
274 }
275 #endif
276 
277 /******************************************************************************
278  *                                                                            *
279  * Function: __zbx_DBexecute                                                  *
280  *                                                                            *
281  * Purpose: execute a non-select statement                                    *
282  *                                                                            *
283  * Comments: retry until DB is up                                             *
284  *                                                                            *
285  ******************************************************************************/
DBexecute(const char * fmt,...)286 int	DBexecute(const char *fmt, ...)
287 {
288 	va_list	args;
289 	int	rc;
290 
291 	va_start(args, fmt);
292 
293 	rc = zbx_db_vexecute(fmt, args);
294 
295 	while (ZBX_DB_DOWN == rc)
296 	{
297 		DBclose();
298 		DBconnect(ZBX_DB_CONNECT_NORMAL);
299 
300 		if (ZBX_DB_DOWN == (rc = zbx_db_vexecute(fmt, args)))
301 		{
302 			zabbix_log(LOG_LEVEL_ERR, "database is down: retrying in %d seconds", ZBX_DB_WAIT_DOWN);
303 			connection_failure = 1;
304 			sleep(ZBX_DB_WAIT_DOWN);
305 		}
306 	}
307 
308 	va_end(args);
309 
310 	return rc;
311 }
312 
313 /******************************************************************************
314  *                                                                            *
315  * Function: __zbx_DBexecute_once                                             *
316  *                                                                            *
317  * Purpose: execute a non-select statement                                    *
318  *                                                                            *
319  * Comments: don't retry if DB is down                                        *
320  *                                                                            *
321  ******************************************************************************/
DBexecute_once(const char * fmt,...)322 int	DBexecute_once(const char *fmt, ...)
323 {
324 	va_list	args;
325 	int	rc;
326 
327 	va_start(args, fmt);
328 
329 	rc = zbx_db_vexecute(fmt, args);
330 
331 	va_end(args);
332 
333 	return rc;
334 }
335 
336 /******************************************************************************
337  *                                                                            *
338  * Function: DBis_null                                                        *
339  *                                                                            *
340  * Purpose: check if numeric field value is null                              *
341  *                                                                            *
342  * Parameters: field - [IN] field value to be checked                         *
343  *                                                                            *
344  * Return value: SUCCEED - field value is null                                *
345  *               FAIL    - otherwise                                          *
346  *                                                                            *
347  * Comments: ATTENTION! This function should only be used with numeric fields *
348  *           since on Oracle empty string is returned instead of NULL and it  *
349  *           is not possible to differentiate empty string from NULL string   *
350  *                                                                            *
351  ******************************************************************************/
DBis_null(const char * field)352 int	DBis_null(const char *field)
353 {
354 	return zbx_db_is_null(field);
355 }
356 
DBfetch(DB_RESULT result)357 DB_ROW	DBfetch(DB_RESULT result)
358 {
359 	return zbx_db_fetch(result);
360 }
361 
362 /******************************************************************************
363  *                                                                            *
364  * Function: DBselect_once                                                    *
365  *                                                                            *
366  * Purpose: execute a select statement                                        *
367  *                                                                            *
368  ******************************************************************************/
DBselect_once(const char * fmt,...)369 DB_RESULT	DBselect_once(const char *fmt, ...)
370 {
371 	va_list		args;
372 	DB_RESULT	rc;
373 
374 	va_start(args, fmt);
375 
376 	rc = zbx_db_vselect(fmt, args);
377 
378 	va_end(args);
379 
380 	return rc;
381 }
382 
383 /******************************************************************************
384  *                                                                            *
385  * Function: DBselect                                                         *
386  *                                                                            *
387  * Purpose: execute a select statement                                        *
388  *                                                                            *
389  * Comments: retry until DB is up                                             *
390  *                                                                            *
391  ******************************************************************************/
DBselect(const char * fmt,...)392 DB_RESULT	DBselect(const char *fmt, ...)
393 {
394 	va_list		args;
395 	DB_RESULT	rc;
396 
397 	va_start(args, fmt);
398 
399 	rc = zbx_db_vselect(fmt, args);
400 
401 	while ((DB_RESULT)ZBX_DB_DOWN == rc)
402 	{
403 		DBclose();
404 		DBconnect(ZBX_DB_CONNECT_NORMAL);
405 
406 		if ((DB_RESULT)ZBX_DB_DOWN == (rc = zbx_db_vselect(fmt, args)))
407 		{
408 			zabbix_log(LOG_LEVEL_ERR, "database is down: retrying in %d seconds", ZBX_DB_WAIT_DOWN);
409 			connection_failure = 1;
410 			sleep(ZBX_DB_WAIT_DOWN);
411 		}
412 	}
413 
414 	va_end(args);
415 
416 	return rc;
417 }
418 
419 /******************************************************************************
420  *                                                                            *
421  * Function: DBselectN                                                        *
422  *                                                                            *
423  * Purpose: execute a select statement and get the first N entries            *
424  *                                                                            *
425  * Comments: retry until DB is up                                             *
426  *                                                                            *
427  ******************************************************************************/
DBselectN(const char * query,int n)428 DB_RESULT	DBselectN(const char *query, int n)
429 {
430 	DB_RESULT	rc;
431 
432 	rc = zbx_db_select_n(query, n);
433 
434 	while ((DB_RESULT)ZBX_DB_DOWN == rc)
435 	{
436 		DBclose();
437 		DBconnect(ZBX_DB_CONNECT_NORMAL);
438 
439 		if ((DB_RESULT)ZBX_DB_DOWN == (rc = zbx_db_select_n(query, n)))
440 		{
441 			zabbix_log(LOG_LEVEL_ERR, "database is down: retrying in %d seconds", ZBX_DB_WAIT_DOWN);
442 			connection_failure = 1;
443 			sleep(ZBX_DB_WAIT_DOWN);
444 		}
445 	}
446 
447 	return rc;
448 }
449 
DBget_row_count(const char * table_name)450 int	DBget_row_count(const char *table_name)
451 {
452 	const char	*__function_name = "DBget_row_count";
453 
454 	int		count = 0;
455 	DB_RESULT	result;
456 	DB_ROW		row;
457 
458 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() table_name:'%s'", __function_name, table_name);
459 
460 	result = DBselect("select count(*) from %s", table_name);
461 
462 	if (NULL != (row = DBfetch(result)))
463 		count = atoi(row[0]);
464 	DBfree_result(result);
465 
466 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, count);
467 
468 	return count;
469 }
470 
DBget_proxy_lastaccess(const char * hostname,int * lastaccess,char ** error)471 int	DBget_proxy_lastaccess(const char *hostname, int *lastaccess, char **error)
472 {
473 	const char	*__function_name = "DBget_proxy_lastaccess";
474 
475 	DB_RESULT	result;
476 	DB_ROW		row;
477 	char		*host_esc;
478 	int		ret = FAIL;
479 
480 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
481 
482 	host_esc = DBdyn_escape_string(hostname);
483 	result = DBselect("select lastaccess from hosts where host='%s' and status in (%d,%d)",
484 			host_esc, HOST_STATUS_PROXY_ACTIVE, HOST_STATUS_PROXY_PASSIVE);
485 	zbx_free(host_esc);
486 
487 	if (NULL != (row = DBfetch(result)))
488 	{
489 		*lastaccess = atoi(row[0]);
490 		ret = SUCCEED;
491 	}
492 	else
493 		*error = zbx_dsprintf(*error, "Proxy \"%s\" does not exist.", hostname);
494 	DBfree_result(result);
495 
496 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
497 
498 	return ret;
499 }
500 
501 #ifdef HAVE_MYSQL
get_string_field_size(unsigned char type)502 static size_t	get_string_field_size(unsigned char type)
503 {
504 	switch(type)
505 	{
506 		case ZBX_TYPE_LONGTEXT:
507 			return ZBX_SIZE_T_MAX;
508 		case ZBX_TYPE_CHAR:
509 		case ZBX_TYPE_TEXT:
510 		case ZBX_TYPE_SHORTTEXT:
511 			return 65535u;
512 		default:
513 			THIS_SHOULD_NEVER_HAPPEN;
514 			exit(EXIT_FAILURE);
515 	}
516 }
517 #elif defined(HAVE_ORACLE)
get_string_field_size(unsigned char type)518 static size_t	get_string_field_size(unsigned char type)
519 {
520 	switch(type)
521 	{
522 		case ZBX_TYPE_LONGTEXT:
523 		case ZBX_TYPE_TEXT:
524 			return ZBX_SIZE_T_MAX;
525 		case ZBX_TYPE_CHAR:
526 		case ZBX_TYPE_SHORTTEXT:
527 			return 4000u;
528 		default:
529 			THIS_SHOULD_NEVER_HAPPEN;
530 			exit(EXIT_FAILURE);
531 	}
532 }
533 #endif
534 
535 /******************************************************************************
536  *                                                                            *
537  * Function: DBdyn_escape_string_len                                          *
538  *                                                                            *
539  ******************************************************************************/
DBdyn_escape_string_len(const char * src,size_t length)540 char	*DBdyn_escape_string_len(const char *src, size_t length)
541 {
542 #if defined(HAVE_IBM_DB2)	/* IBM DB2 fields are limited by bytes rather than characters */
543 	return zbx_db_dyn_escape_string(src, length, ZBX_SIZE_T_MAX, ESCAPE_SEQUENCE_ON);
544 #else
545 	return zbx_db_dyn_escape_string(src, ZBX_SIZE_T_MAX, length, ESCAPE_SEQUENCE_ON);
546 #endif
547 }
548 
549 /******************************************************************************
550  *                                                                            *
551  * Function: DBdyn_escape_string                                              *
552  *                                                                            *
553  ******************************************************************************/
DBdyn_escape_string(const char * src)554 char	*DBdyn_escape_string(const char *src)
555 {
556 	return zbx_db_dyn_escape_string(src, ZBX_SIZE_T_MAX, ZBX_SIZE_T_MAX, ESCAPE_SEQUENCE_ON);
557 }
558 
559 /******************************************************************************
560  *                                                                            *
561  * Function: DBdyn_escape_field_len                                           *
562  *                                                                            *
563  ******************************************************************************/
DBdyn_escape_field_len(const ZBX_FIELD * field,const char * src,zbx_escape_sequence_t flag)564 static char	*DBdyn_escape_field_len(const ZBX_FIELD *field, const char *src, zbx_escape_sequence_t flag)
565 {
566 	size_t	length;
567 
568 	if (ZBX_TYPE_LONGTEXT == field->type && 0 == field->length)
569 		length = ZBX_SIZE_T_MAX;
570 	else
571 		length = field->length;
572 
573 #if defined(HAVE_MYSQL) || defined(HAVE_ORACLE)
574 	return zbx_db_dyn_escape_string(src, get_string_field_size(field->type), length, flag);
575 #elif defined(HAVE_IBM_DB2)	/* IBM DB2 fields are limited by bytes rather than characters */
576 	return zbx_db_dyn_escape_string(src, length, ZBX_SIZE_T_MAX, flag);
577 #else
578 	return zbx_db_dyn_escape_string(src, ZBX_SIZE_T_MAX, length, flag);
579 #endif
580 }
581 
582 /******************************************************************************
583  *                                                                            *
584  * Function: DBdyn_escape_field                                               *
585  *                                                                            *
586  ******************************************************************************/
DBdyn_escape_field(const char * table_name,const char * field_name,const char * src)587 char	*DBdyn_escape_field(const char *table_name, const char *field_name, const char *src)
588 {
589 	const ZBX_TABLE	*table;
590 	const ZBX_FIELD	*field;
591 
592 	if (NULL == (table = DBget_table(table_name)) || NULL == (field = DBget_field(table, field_name)))
593 	{
594 		zabbix_log(LOG_LEVEL_CRIT, "invalid table: \"%s\" field: \"%s\"", table_name, field_name);
595 		exit(EXIT_FAILURE);
596 	}
597 
598 	return DBdyn_escape_field_len(field, src, ESCAPE_SEQUENCE_ON);
599 }
600 
601 /******************************************************************************
602  *                                                                            *
603  * Function: DBdyn_escape_like_pattern                                        *
604  *                                                                            *
605  ******************************************************************************/
DBdyn_escape_like_pattern(const char * src)606 char	*DBdyn_escape_like_pattern(const char *src)
607 {
608 	return zbx_db_dyn_escape_like_pattern(src);
609 }
610 
DBget_table(const char * tablename)611 const ZBX_TABLE	*DBget_table(const char *tablename)
612 {
613 	int	t;
614 
615 	for (t = 0; NULL != tables[t].table; t++)
616 	{
617 		if (0 == strcmp(tables[t].table, tablename))
618 			return &tables[t];
619 	}
620 
621 	return NULL;
622 }
623 
DBget_field(const ZBX_TABLE * table,const char * fieldname)624 const ZBX_FIELD	*DBget_field(const ZBX_TABLE *table, const char *fieldname)
625 {
626 	int	f;
627 
628 	for (f = 0; NULL != table->fields[f].name; f++)
629 	{
630 		if (0 == strcmp(table->fields[f].name, fieldname))
631 			return &table->fields[f];
632 	}
633 
634 	return NULL;
635 }
636 
637 /******************************************************************************
638  *                                                                            *
639  * Function: DBget_nextid                                                     *
640  *                                                                            *
641  * Purpose: gets a new identifier(s) for a specified table                    *
642  *                                                                            *
643  * Parameters: tablename - [IN] the name of a table                           *
644  *             num       - [IN] the number of reserved records                *
645  *                                                                            *
646  * Return value: first reserved identifier                                    *
647  *                                                                            *
648  ******************************************************************************/
DBget_nextid(const char * tablename,int num)649 static zbx_uint64_t	DBget_nextid(const char *tablename, int num)
650 {
651 	const char	*__function_name = "DBget_nextid";
652 
653 	DB_RESULT	result;
654 	DB_ROW		row;
655 	zbx_uint64_t	ret1, ret2;
656 	zbx_uint64_t	min = 0, max = ZBX_DB_MAX_ID;
657 	int		found = FAIL, dbres;
658 	const ZBX_TABLE	*table;
659 
660 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() tablename:'%s'", __function_name, tablename);
661 
662 	table = DBget_table(tablename);
663 
664 	while (FAIL == found)
665 	{
666 		/* avoid eternal loop within failed transaction */
667 		if (0 < zbx_db_txn_level() && 0 != zbx_db_txn_error())
668 		{
669 			zabbix_log(LOG_LEVEL_DEBUG, "End of %s() transaction failed", __function_name);
670 			return 0;
671 		}
672 
673 		result = DBselect("select nextid from ids where table_name='%s' and field_name='%s'",
674 				table->table, table->recid);
675 
676 		if (NULL == (row = DBfetch(result)))
677 		{
678 			DBfree_result(result);
679 
680 			result = DBselect("select max(%s) from %s where %s between " ZBX_FS_UI64 " and " ZBX_FS_UI64,
681 					table->recid, table->table, table->recid, min, max);
682 
683 			if (NULL == (row = DBfetch(result)) || SUCCEED == DBis_null(row[0]))
684 			{
685 				ret1 = min;
686 			}
687 			else
688 			{
689 				ZBX_STR2UINT64(ret1, row[0]);
690 				if (ret1 >= max)
691 				{
692 					zabbix_log(LOG_LEVEL_CRIT, "maximum number of id's exceeded"
693 							" [table:%s, field:%s, id:" ZBX_FS_UI64 "]",
694 							table->table, table->recid, ret1);
695 					exit(EXIT_FAILURE);
696 				}
697 			}
698 
699 			DBfree_result(result);
700 
701 			dbres = DBexecute("insert into ids (table_name,field_name,nextid)"
702 					" values ('%s','%s'," ZBX_FS_UI64 ")",
703 					table->table, table->recid, ret1);
704 
705 			if (ZBX_DB_OK > dbres)
706 			{
707 				/* solving the problem of an invisible record created in a parallel transaction */
708 				DBexecute("update ids set nextid=nextid+1 where table_name='%s' and field_name='%s'",
709 						table->table, table->recid);
710 			}
711 
712 			continue;
713 		}
714 		else
715 		{
716 			ZBX_STR2UINT64(ret1, row[0]);
717 			DBfree_result(result);
718 
719 			if (ret1 < min || ret1 >= max)
720 			{
721 				DBexecute("delete from ids where table_name='%s' and field_name='%s'",
722 						table->table, table->recid);
723 				continue;
724 			}
725 
726 			DBexecute("update ids set nextid=nextid+%d where table_name='%s' and field_name='%s'",
727 					num, table->table, table->recid);
728 
729 			result = DBselect("select nextid from ids where table_name='%s' and field_name='%s'",
730 					table->table, table->recid);
731 
732 			if (NULL != (row = DBfetch(result)) && SUCCEED != DBis_null(row[0]))
733 			{
734 				ZBX_STR2UINT64(ret2, row[0]);
735 
736 				if (ret1 + num == ret2)
737 					found = SUCCEED;
738 			}
739 			else
740 				THIS_SHOULD_NEVER_HAPPEN;
741 
742 			DBfree_result(result);
743 		}
744 	}
745 
746 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():" ZBX_FS_UI64 " table:'%s' recid:'%s'",
747 			__function_name, ret2 - num + 1, table->table, table->recid);
748 
749 	return ret2 - num + 1;
750 }
751 
DBget_maxid_num(const char * tablename,int num)752 zbx_uint64_t	DBget_maxid_num(const char *tablename, int num)
753 {
754 	if (0 == strcmp(tablename, "events") ||
755 			0 == strcmp(tablename, "event_tag") ||
756 			0 == strcmp(tablename, "problem_tag") ||
757 			0 == strcmp(tablename, "dservices") ||
758 			0 == strcmp(tablename, "dhosts") ||
759 			0 == strcmp(tablename, "alerts") ||
760 			0 == strcmp(tablename, "escalations") ||
761 			0 == strcmp(tablename, "autoreg_host") ||
762 			0 == strcmp(tablename, "event_suppress"))
763 		return DCget_nextid(tablename, num);
764 
765 	return DBget_nextid(tablename, num);
766 }
767 
768 #define MAX_EXPRESSIONS	950
769 
770 #ifdef HAVE_ORACLE
771 #define MIN_NUM_BETWEEN	5	/* minimum number of consecutive values for using "between <id1> and <idN>" */
772 
773 /******************************************************************************
774  *                                                                            *
775  * Function: DBadd_condition_alloc_btw                                        *
776  *                                                                            *
777  * Purpose: Takes an initial part of SQL query and appends a generated        *
778  *          WHERE condition. The WHERE condition is generated from the given  *
779  *          list of values as a mix of <fieldname> BETWEEN <id1> AND <idN>"   *
780  *                                                                            *
781  * Parameters: sql        - [IN/OUT] buffer for SQL query construction        *
782  *             sql_alloc  - [IN/OUT] size of the 'sql' buffer                 *
783  *             sql_offset - [IN/OUT] current position in the 'sql' buffer     *
784  *             fieldname  - [IN] field name to be used in SQL WHERE condition *
785  *             values     - [IN] array of numerical values sorted in          *
786  *                               ascending order to be included in WHERE      *
787  *             num        - [IN] number of elements in 'values' array         *
788  *             seq_len    - [OUT] - array of sequential chains                *
789  *             seq_num    - [OUT] - length of seq_len                         *
790  *             in_num     - [OUT] - number of id for 'IN'                     *
791  *             between_num- [OUT] - number of sequential chains for 'BETWEEN' *
792  *                                                                            *
793  ******************************************************************************/
DBadd_condition_alloc_btw(char ** sql,size_t * sql_alloc,size_t * sql_offset,const char * fieldname,const zbx_uint64_t * values,const int num,int ** seq_len,int * seq_num,int * in_num,int * between_num)794 static void	DBadd_condition_alloc_btw(char **sql, size_t *sql_alloc, size_t *sql_offset, const char *fieldname,
795 		const zbx_uint64_t *values, const int num, int **seq_len, int *seq_num, int *in_num, int *between_num)
796 {
797 	int		i, len, first, start;
798 	zbx_uint64_t	value;
799 
800 	/* Store lengths of consecutive sequences of values in a temporary array 'seq_len'. */
801 	/* An isolated value is represented as a sequence with length 1. */
802 	*seq_len = (int *)zbx_malloc(*seq_len, num * sizeof(int));
803 
804 	for (i = 1, *seq_num = 0, value = values[0], len = 1; i < num; i++)
805 	{
806 		if (values[i] != ++value)
807 		{
808 			if (MIN_NUM_BETWEEN <= len)
809 				(*between_num)++;
810 			else
811 				*in_num += len;
812 
813 			(*seq_len)[(*seq_num)++] = len;
814 			len = 1;
815 			value = values[i];
816 		}
817 		else
818 			len++;
819 	}
820 
821 	if (MIN_NUM_BETWEEN <= len)
822 		(*between_num)++;
823 	else
824 		*in_num += len;
825 
826 	(*seq_len)[(*seq_num)++] = len;
827 
828 	if (MAX_EXPRESSIONS < *in_num || 1 < *between_num || (0 < *in_num && 0 < *between_num))
829 		zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, '(');
830 
831 	/* compose "between"s */
832 	for (i = 0, first = 1, start = 0; i < *seq_num; i++)
833 	{
834 		if (MIN_NUM_BETWEEN <= (*seq_len)[i])
835 		{
836 			if (1 != first)
837 			{
838 					zbx_strcpy_alloc(sql, sql_alloc, sql_offset, " or ");
839 			}
840 			else
841 				first = 0;
842 
843 			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%s between " ZBX_FS_UI64 " and " ZBX_FS_UI64,
844 					fieldname, values[start], values[start + (*seq_len)[i] - 1]);
845 		}
846 
847 		start += (*seq_len)[i];
848 	}
849 
850 	if (0 < *in_num && 0 < *between_num)
851 	{
852 		zbx_strcpy_alloc(sql, sql_alloc, sql_offset, " or ");
853 	}
854 }
855 #endif
856 
857 /******************************************************************************
858  *                                                                            *
859  * Function: DBadd_condition_alloc                                            *
860  *                                                                            *
861  * Purpose: Takes an initial part of SQL query and appends a generated        *
862  *          WHERE condition. The WHERE condition is generated from the given  *
863  *          list of values as a mix of <fieldname> BETWEEN <id1> AND <idN>"   *
864  *          and "<fieldname> IN (<id1>,<id2>,...,<idN>)" elements.            *
865  *                                                                            *
866  * Parameters: sql        - [IN/OUT] buffer for SQL query construction        *
867  *             sql_alloc  - [IN/OUT] size of the 'sql' buffer                 *
868  *             sql_offset - [IN/OUT] current position in the 'sql' buffer     *
869  *             fieldname  - [IN] field name to be used in SQL WHERE condition *
870  *             values     - [IN] array of numerical values sorted in          *
871  *                               ascending order to be included in WHERE      *
872  *             num        - [IN] number of elements in 'values' array         *
873  *                                                                            *
874  ******************************************************************************/
DBadd_condition_alloc(char ** sql,size_t * sql_alloc,size_t * sql_offset,const char * fieldname,const zbx_uint64_t * values,const int num)875 void	DBadd_condition_alloc(char **sql, size_t *sql_alloc, size_t *sql_offset, const char *fieldname,
876 		const zbx_uint64_t *values, const int num)
877 {
878 #ifdef HAVE_ORACLE
879 	int		start, between_num = 0, in_num = 0, seq_num;
880 	int		*seq_len = NULL;
881 #endif
882 	int		i, in_cnt;
883 #if defined(HAVE_SQLITE3)
884 	int		expr_num, expr_cnt = 0;
885 #endif
886 	if (0 == num)
887 		return;
888 
889 	zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, ' ');
890 #ifdef HAVE_ORACLE
891 	DBadd_condition_alloc_btw(sql, sql_alloc, sql_offset, fieldname, values, num, &seq_len, &seq_num, &in_num,
892 			&between_num);
893 
894 	if (1 < in_num)
895 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%s in (", fieldname);
896 
897 	/* compose "in"s */
898 	for (i = 0, in_cnt = 0, start = 0; i < seq_num; i++)
899 	{
900 		if (MIN_NUM_BETWEEN > seq_len[i])
901 		{
902 			if (1 == in_num)
903 #else
904 	if (MAX_EXPRESSIONS < num)
905 		zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, '(');
906 
907 #if	defined(HAVE_SQLITE3)
908 	expr_num = (num + MAX_EXPRESSIONS - 1) / MAX_EXPRESSIONS;
909 
910 	if (MAX_EXPRESSIONS < expr_num)
911 		zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, '(');
912 #endif
913 
914 	if (1 < num)
915 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%s in (", fieldname);
916 
917 	/* compose "in"s */
918 	for (i = 0, in_cnt = 0; i < num; i++)
919 	{
920 			if (1 == num)
921 #endif
922 			{
923 				zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%s=" ZBX_FS_UI64, fieldname,
924 #ifdef HAVE_ORACLE
925 						values[start]);
926 #else
927 						values[i]);
928 #endif
929 				break;
930 			}
931 			else
932 			{
933 #ifdef HAVE_ORACLE
934 				do
935 				{
936 #endif
937 					if (MAX_EXPRESSIONS == in_cnt)
938 					{
939 						in_cnt = 0;
940 						(*sql_offset)--;
941 #if defined(HAVE_SQLITE3)
942 						if (MAX_EXPRESSIONS == ++expr_cnt)
943 						{
944 							zbx_snprintf_alloc(sql, sql_alloc, sql_offset, ")) or (%s in (",
945 									fieldname);
946 							expr_cnt = 0;
947 						}
948 						else
949 						{
950 #endif
951 							zbx_snprintf_alloc(sql, sql_alloc, sql_offset, ") or %s in (",
952 									fieldname);
953 #if defined(HAVE_SQLITE3)
954 						}
955 #endif
956 					}
957 
958 					in_cnt++;
959 					zbx_snprintf_alloc(sql, sql_alloc, sql_offset, ZBX_FS_UI64 ",",
960 #ifdef HAVE_ORACLE
961 							values[start++]);
962 				}
963 				while (0 != --seq_len[i]);
964 			}
965 		}
966 		else
967 			start += seq_len[i];
968 	}
969 
970 	zbx_free(seq_len);
971 
972 	if (1 < in_num)
973 #else
974 							values[i]);
975 			}
976 	}
977 
978 	if (1 < num)
979 #endif
980 	{
981 		(*sql_offset)--;
982 		zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, ')');
983 	}
984 
985 #if defined(HAVE_SQLITE3)
986 	if (MAX_EXPRESSIONS < expr_num)
987 		zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, ')');
988 #endif
989 #ifdef HAVE_ORACLE
990 	if (MAX_EXPRESSIONS < in_num || 1 < between_num || (0 < in_num && 0 < between_num))
991 #else
992 	if (MAX_EXPRESSIONS < num)
993 #endif
994 		zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, ')');
995 
996 #undef MAX_EXPRESSIONS
997 #ifdef HAVE_ORACLE
998 #undef MIN_NUM_BETWEEN
999 #endif
1000 }
1001 
1002 /******************************************************************************
1003  *                                                                            *
1004  * Function: DBadd_str_condition_alloc                                        *
1005  *                                                                            *
1006  * Purpose: This function is similar to DBadd_condition_alloc(), except it is *
1007  *          designed for generating WHERE conditions for strings. Hence, this *
1008  *          function is simpler, because only IN condition is possible.       *
1009  *                                                                            *
1010  * Parameters: sql        - [IN/OUT] buffer for SQL query construction        *
1011  *             sql_alloc  - [IN/OUT] size of the 'sql' buffer                 *
1012  *             sql_offset - [IN/OUT] current position in the 'sql' buffer     *
1013  *             fieldname  - [IN] field name to be used in SQL WHERE condition *
1014  *             values     - [IN] array of string values                       *
1015  *             num        - [IN] number of elements in 'values' array         *
1016  *                                                                            *
1017  * Comments: To support Oracle empty values are checked separately (is null   *
1018  *           for Oracle and ='' for the other databases).                     *
1019  *                                                                            *
1020  ******************************************************************************/
DBadd_str_condition_alloc(char ** sql,size_t * sql_alloc,size_t * sql_offset,const char * fieldname,const char ** values,const int num)1021 void	DBadd_str_condition_alloc(char **sql, size_t *sql_alloc, size_t *sql_offset, const char *fieldname,
1022 		const char **values, const int num)
1023 {
1024 #define MAX_EXPRESSIONS	950
1025 
1026 	int	i, cnt = 0;
1027 	char	*value_esc;
1028 	int	values_num = 0, empty_num = 0;
1029 
1030 	if (0 == num)
1031 		return;
1032 
1033 	zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, ' ');
1034 
1035 	for (i = 0; i < num; i++)
1036 	{
1037 		if ('\0' == *values[i])
1038 			empty_num++;
1039 		else
1040 			values_num++;
1041 	}
1042 
1043 	if (MAX_EXPRESSIONS < values_num || (0 != values_num && 0 != empty_num))
1044 		zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, '(');
1045 
1046 	if (0 != empty_num)
1047 	{
1048 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%s" ZBX_SQL_STRCMP, fieldname, ZBX_SQL_STRVAL_EQ(""));
1049 
1050 		if (0 == values_num)
1051 			return;
1052 
1053 		zbx_strcpy_alloc(sql, sql_alloc, sql_offset, " or ");
1054 	}
1055 
1056 	if (1 == values_num)
1057 	{
1058 		for (i = 0; i < num; i++)
1059 		{
1060 			if ('\0' == *values[i])
1061 				continue;
1062 
1063 			value_esc = DBdyn_escape_string(values[i]);
1064 			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%s='%s'", fieldname, value_esc);
1065 			zbx_free(value_esc);
1066 		}
1067 
1068 		if (0 != empty_num)
1069 			zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, ')');
1070 		return;
1071 	}
1072 
1073 	zbx_strcpy_alloc(sql, sql_alloc, sql_offset, fieldname);
1074 	zbx_strcpy_alloc(sql, sql_alloc, sql_offset, " in (");
1075 
1076 	for (i = 0; i < num; i++)
1077 	{
1078 		if ('\0' == *values[i])
1079 			continue;
1080 
1081 		if (MAX_EXPRESSIONS == cnt)
1082 		{
1083 			cnt = 0;
1084 			(*sql_offset)--;
1085 			zbx_strcpy_alloc(sql, sql_alloc, sql_offset, ") or ");
1086 			zbx_strcpy_alloc(sql, sql_alloc, sql_offset, fieldname);
1087 			zbx_strcpy_alloc(sql, sql_alloc, sql_offset, " in (");
1088 		}
1089 
1090 		value_esc = DBdyn_escape_string(values[i]);
1091 		zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, '\'');
1092 		zbx_strcpy_alloc(sql, sql_alloc, sql_offset, value_esc);
1093 		zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "',");
1094 		zbx_free(value_esc);
1095 
1096 		cnt++;
1097 	}
1098 
1099 	(*sql_offset)--;
1100 	zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, ')');
1101 
1102 	if (MAX_EXPRESSIONS < values_num || 0 != empty_num)
1103 		zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, ')');
1104 
1105 #undef MAX_EXPRESSIONS
1106 }
1107 
1108 static char	buf_string[640];
1109 
1110 /******************************************************************************
1111  *                                                                            *
1112  * Function: zbx_host_string                                                  *
1113  *                                                                            *
1114  * Return value: <host> or "???" if host not found                            *
1115  *                                                                            *
1116  * Author: Alexander Vladishev                                                *
1117  *                                                                            *
1118  ******************************************************************************/
zbx_host_string(zbx_uint64_t hostid)1119 const char	*zbx_host_string(zbx_uint64_t hostid)
1120 {
1121 	DB_RESULT	result;
1122 	DB_ROW		row;
1123 
1124 	result = DBselect(
1125 			"select host"
1126 			" from hosts"
1127 			" where hostid=" ZBX_FS_UI64,
1128 			hostid);
1129 
1130 	if (NULL != (row = DBfetch(result)))
1131 		zbx_snprintf(buf_string, sizeof(buf_string), "%s", row[0]);
1132 	else
1133 		zbx_snprintf(buf_string, sizeof(buf_string), "???");
1134 
1135 	DBfree_result(result);
1136 
1137 	return buf_string;
1138 }
1139 
1140 /******************************************************************************
1141  *                                                                            *
1142  * Function: zbx_host_key_string                                              *
1143  *                                                                            *
1144  * Return value: <host>:<key> or "???" if item not found                      *
1145  *                                                                            *
1146  * Author: Alexander Vladishev                                                *
1147  *                                                                            *
1148  ******************************************************************************/
zbx_host_key_string(zbx_uint64_t itemid)1149 const char	*zbx_host_key_string(zbx_uint64_t itemid)
1150 {
1151 	DB_RESULT	result;
1152 	DB_ROW		row;
1153 
1154 	result = DBselect(
1155 			"select h.host,i.key_"
1156 			" from hosts h,items i"
1157 			" where h.hostid=i.hostid"
1158 				" and i.itemid=" ZBX_FS_UI64,
1159 			itemid);
1160 
1161 	if (NULL != (row = DBfetch(result)))
1162 		zbx_snprintf(buf_string, sizeof(buf_string), "%s:%s", row[0], row[1]);
1163 	else
1164 		zbx_snprintf(buf_string, sizeof(buf_string), "???");
1165 
1166 	DBfree_result(result);
1167 
1168 	return buf_string;
1169 }
1170 
1171 /******************************************************************************
1172  *                                                                            *
1173  * Function: zbx_check_user_permissions                                       *
1174  *                                                                            *
1175  * Purpose: check if user has access rights to information - full name, alias,*
1176  *          Email, SMS, Jabber, etc                                           *
1177  *                                                                            *
1178  * Parameters: userid           - [IN] user who owns the information          *
1179  *             recipient_userid - [IN] user who will receive the information  *
1180  *                                     can be NULL for remote command         *
1181  *                                                                            *
1182  * Return value: SUCCEED - if information receiving user has access rights    *
1183  *               FAIL    - otherwise                                          *
1184  *                                                                            *
1185  * Comments: Users has access rights or can view personal information only    *
1186  *           about themselves and other user who belong to their group.       *
1187  *           "Zabbix Super Admin" can view and has access rights to           *
1188  *           information about any user.                                      *
1189  *                                                                            *
1190  ******************************************************************************/
zbx_check_user_permissions(const zbx_uint64_t * userid,const zbx_uint64_t * recipient_userid)1191 int	zbx_check_user_permissions(const zbx_uint64_t *userid, const zbx_uint64_t *recipient_userid)
1192 {
1193 	const char	*__function_name = "zbx_check_user_permissions";
1194 
1195 	DB_RESULT	result;
1196 	DB_ROW		row;
1197 	int		user_type = -1, ret = SUCCEED;
1198 
1199 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1200 
1201 	if (NULL == recipient_userid || *userid == *recipient_userid)
1202 		goto out;
1203 
1204 	result = DBselect("select type from users where userid=" ZBX_FS_UI64, *recipient_userid);
1205 
1206 	if (NULL != (row = DBfetch(result)) && FAIL == DBis_null(row[0]))
1207 		user_type = atoi(row[0]);
1208 	DBfree_result(result);
1209 
1210 	if (-1 == user_type)
1211 	{
1212 		zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot check permissions", __function_name);
1213 		ret = FAIL;
1214 		goto out;
1215 	}
1216 
1217 	if (USER_TYPE_SUPER_ADMIN != user_type)
1218 	{
1219 		/* check if users are from the same user group */
1220 		result = DBselect(
1221 				"select null"
1222 				" from users_groups ug1"
1223 				" where ug1.userid=" ZBX_FS_UI64
1224 					" and exists (select null"
1225 						" from users_groups ug2"
1226 						" where ug1.usrgrpid=ug2.usrgrpid"
1227 							" and ug2.userid=" ZBX_FS_UI64
1228 					")",
1229 				*userid, *recipient_userid);
1230 
1231 		if (NULL == DBfetch(result))
1232 			ret = FAIL;
1233 		DBfree_result(result);
1234 	}
1235 out:
1236 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1237 
1238 	return ret;
1239 }
1240 
1241 /******************************************************************************
1242  *                                                                            *
1243  * Function: zbx_user_string                                                  *
1244  *                                                                            *
1245  * Return value: "Name Surname (Alias)" or "unknown" if user not found        *
1246  *                                                                            *
1247  * Author: Alexander Vladishev                                                *
1248  *                                                                            *
1249  ******************************************************************************/
zbx_user_string(zbx_uint64_t userid)1250 const char	*zbx_user_string(zbx_uint64_t userid)
1251 {
1252 	DB_RESULT	result;
1253 	DB_ROW		row;
1254 
1255 	result = DBselect("select name,surname,alias from users where userid=" ZBX_FS_UI64, userid);
1256 
1257 	if (NULL != (row = DBfetch(result)))
1258 		zbx_snprintf(buf_string, sizeof(buf_string), "%s %s (%s)", row[0], row[1], row[2]);
1259 	else
1260 		zbx_snprintf(buf_string, sizeof(buf_string), "unknown");
1261 
1262 	DBfree_result(result);
1263 
1264 	return buf_string;
1265 }
1266 
1267 /******************************************************************************
1268  *                                                                            *
1269  * Function: DBsql_id_cmp                                                     *
1270  *                                                                            *
1271  * Purpose: construct where condition                                         *
1272  *                                                                            *
1273  * Return value: "=<id>" if id not equal zero,                                *
1274  *               otherwise " is null"                                         *
1275  *                                                                            *
1276  * Author: Alexander Vladishev                                                *
1277  *                                                                            *
1278  * Comments: NB! Do not use this function more than once in same SQL query    *
1279  *                                                                            *
1280  ******************************************************************************/
DBsql_id_cmp(zbx_uint64_t id)1281 const char	*DBsql_id_cmp(zbx_uint64_t id)
1282 {
1283 	static char		buf[22];	/* 1 - '=', 20 - value size, 1 - '\0' */
1284 	static const char	is_null[9] = " is null";
1285 
1286 	if (0 == id)
1287 		return is_null;
1288 
1289 	zbx_snprintf(buf, sizeof(buf), "=" ZBX_FS_UI64, id);
1290 
1291 	return buf;
1292 }
1293 
1294 /******************************************************************************
1295  *                                                                            *
1296  * Function: DBregister_host                                                  *
1297  *                                                                            *
1298  * Purpose: register unknown host and generate event                          *
1299  *                                                                            *
1300  * Parameters: host - host name                                               *
1301  *                                                                            *
1302  * Author: Alexander Vladishev                                                *
1303  *                                                                            *
1304  ******************************************************************************/
DBregister_host(zbx_uint64_t proxy_hostid,const char * host,const char * ip,const char * dns,unsigned short port,const char * host_metadata,int now)1305 void	DBregister_host(zbx_uint64_t proxy_hostid, const char *host, const char *ip, const char *dns,
1306 		unsigned short port, const char *host_metadata, int now)
1307 {
1308 	zbx_vector_ptr_t	autoreg_hosts;
1309 
1310 	zbx_vector_ptr_create(&autoreg_hosts);
1311 
1312 	DBregister_host_prepare(&autoreg_hosts, host, ip, dns, port, host_metadata, now);
1313 	DBregister_host_flush(&autoreg_hosts, proxy_hostid);
1314 
1315 	DBregister_host_clean(&autoreg_hosts);
1316 	zbx_vector_ptr_destroy(&autoreg_hosts);
1317 }
1318 
DBregister_host_active(void)1319 static int	DBregister_host_active(void)
1320 {
1321 	const char	*__function_name = "DBregister_host_active";
1322 
1323 	DB_RESULT	result;
1324 	int		ret = SUCCEED;
1325 
1326 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1327 
1328 	result = DBselect(
1329 			"select null"
1330 			" from actions"
1331 			" where eventsource=%d"
1332 				" and status=%d",
1333 			EVENT_SOURCE_AUTOREGISTRATION,
1334 			ACTION_STATUS_ACTIVE);
1335 
1336 	if (NULL == DBfetch(result))
1337 		ret = FAIL;
1338 
1339 	DBfree_result(result);
1340 
1341 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1342 
1343 	return ret;
1344 }
1345 
autoreg_host_free(zbx_autoreg_host_t * autoreg_host)1346 static void	autoreg_host_free(zbx_autoreg_host_t *autoreg_host)
1347 {
1348 	zbx_free(autoreg_host->host);
1349 	zbx_free(autoreg_host->ip);
1350 	zbx_free(autoreg_host->dns);
1351 	zbx_free(autoreg_host->host_metadata);
1352 	zbx_free(autoreg_host);
1353 }
1354 
DBregister_host_prepare(zbx_vector_ptr_t * autoreg_hosts,const char * host,const char * ip,const char * dns,unsigned short port,const char * host_metadata,int now)1355 void	DBregister_host_prepare(zbx_vector_ptr_t *autoreg_hosts, const char *host, const char *ip, const char *dns,
1356 		unsigned short port, const char *host_metadata, int now)
1357 {
1358 	zbx_autoreg_host_t	*autoreg_host;
1359 	int 			i;
1360 
1361 	for (i = 0; i < autoreg_hosts->values_num; i++)	/* duplicate check */
1362 	{
1363 		autoreg_host = (zbx_autoreg_host_t *)autoreg_hosts->values[i];
1364 
1365 		if (0 == strcmp(host, autoreg_host->host))
1366 		{
1367 			zbx_vector_ptr_remove(autoreg_hosts, i);
1368 			autoreg_host_free(autoreg_host);
1369 			break;
1370 		}
1371 	}
1372 
1373 	autoreg_host = (zbx_autoreg_host_t *)zbx_malloc(NULL, sizeof(zbx_autoreg_host_t));
1374 	autoreg_host->autoreg_hostid = autoreg_host->hostid = 0;
1375 	autoreg_host->host = zbx_strdup(NULL, host);
1376 	autoreg_host->ip = zbx_strdup(NULL, ip);
1377 	autoreg_host->dns = zbx_strdup(NULL, dns);
1378 	autoreg_host->port = port;
1379 	autoreg_host->host_metadata = zbx_strdup(NULL, host_metadata);
1380 	autoreg_host->now = now;
1381 
1382 	zbx_vector_ptr_append(autoreg_hosts, autoreg_host);
1383 }
1384 
autoreg_get_hosts(zbx_vector_ptr_t * autoreg_hosts,zbx_vector_str_t * hosts)1385 static void	autoreg_get_hosts(zbx_vector_ptr_t *autoreg_hosts, zbx_vector_str_t *hosts)
1386 {
1387 	int	i;
1388 
1389 	for (i = 0; i < autoreg_hosts->values_num; i++)
1390 	{
1391 		zbx_autoreg_host_t	*autoreg_host = (zbx_autoreg_host_t *)autoreg_hosts->values[i];
1392 
1393 		zbx_vector_str_append(hosts, autoreg_host->host);
1394 	}
1395 }
1396 
process_autoreg_hosts(zbx_vector_ptr_t * autoreg_hosts,zbx_uint64_t proxy_hostid)1397 static void	process_autoreg_hosts(zbx_vector_ptr_t *autoreg_hosts, zbx_uint64_t proxy_hostid)
1398 {
1399 	DB_RESULT		result;
1400 	DB_ROW			row;
1401 	zbx_vector_str_t	hosts;
1402 	zbx_uint64_t		current_proxy_hostid;
1403 	char			*sql = NULL;
1404 	size_t			sql_alloc = 256, sql_offset;
1405 	zbx_autoreg_host_t	*autoreg_host;
1406 	int			i;
1407 
1408 	sql = (char *)zbx_malloc(sql, sql_alloc);
1409 	zbx_vector_str_create(&hosts);
1410 
1411 	if (0 != proxy_hostid)
1412 	{
1413 		autoreg_get_hosts(autoreg_hosts, &hosts);
1414 
1415 		/* delete from vector if already exist in hosts table */
1416 		sql_offset = 0;
1417 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1418 				"select h.host,h.hostid,h.proxy_hostid,a.host_metadata,a.autoreg_hostid"
1419 				" from hosts h"
1420 				" left join autoreg_host a"
1421 					" on a.proxy_hostid=h.proxy_hostid and a.host=h.host"
1422 				" where");
1423 		DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "h.host",
1424 				(const char **)hosts.values, hosts.values_num);
1425 
1426 		result = DBselect("%s", sql);
1427 
1428 		while (NULL != (row = DBfetch(result)))
1429 		{
1430 			for (i = 0; i < autoreg_hosts->values_num; i++)
1431 			{
1432 				autoreg_host = (zbx_autoreg_host_t *)autoreg_hosts->values[i];
1433 
1434 				if (0 != strcmp(autoreg_host->host, row[0]))
1435 					continue;
1436 
1437 				ZBX_STR2UINT64(autoreg_host->hostid, row[1]);
1438 				ZBX_DBROW2UINT64(current_proxy_hostid, row[2]);
1439 
1440 				if (current_proxy_hostid != proxy_hostid || SUCCEED == DBis_null(row[4]) ||
1441 						0 != strcmp(autoreg_host->host_metadata, row[3]))
1442 				{
1443 					break;
1444 				}
1445 
1446 				zbx_vector_ptr_remove(autoreg_hosts, i);
1447 				autoreg_host_free(autoreg_host);
1448 
1449 				break;
1450 			}
1451 
1452 		}
1453 		DBfree_result(result);
1454 
1455 		hosts.values_num = 0;
1456 	}
1457 
1458 	if (0 != autoreg_hosts->values_num)
1459 	{
1460 		autoreg_get_hosts(autoreg_hosts, &hosts);
1461 
1462 		/* update autoreg_id in vector if already exists in autoreg_host table */
1463 		sql_offset = 0;
1464 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1465 				"select autoreg_hostid,host"
1466 				" from autoreg_host"
1467 				" where");
1468 		DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "host",
1469 				(const char **)hosts.values, hosts.values_num);
1470 
1471 		result = DBselect("%s", sql);
1472 
1473 		while (NULL != (row = DBfetch(result)))
1474 		{
1475 			for (i = 0; i < autoreg_hosts->values_num; i++)
1476 			{
1477 				autoreg_host = (zbx_autoreg_host_t *)autoreg_hosts->values[i];
1478 
1479 				if (0 == autoreg_host->autoreg_hostid && 0 == strcmp(autoreg_host->host, row[1]))
1480 				{
1481 					ZBX_STR2UINT64(autoreg_host->autoreg_hostid, row[0]);
1482 					break;
1483 				}
1484 			}
1485 		}
1486 		DBfree_result(result);
1487 
1488 		hosts.values_num = 0;
1489 	}
1490 
1491 	zbx_vector_str_destroy(&hosts);
1492 	zbx_free(sql);
1493 }
1494 
compare_autoreg_host_by_hostid(const void * d1,const void * d2)1495 static int	compare_autoreg_host_by_hostid(const void *d1, const void *d2)
1496 {
1497 	const zbx_autoreg_host_t	*p1 = *(const zbx_autoreg_host_t **)d1;
1498 	const zbx_autoreg_host_t	*p2 = *(const zbx_autoreg_host_t **)d2;
1499 
1500 	ZBX_RETURN_IF_NOT_EQUAL(p1->hostid, p2->hostid);
1501 
1502 	return 0;
1503 }
1504 
DBregister_host_flush(zbx_vector_ptr_t * autoreg_hosts,zbx_uint64_t proxy_hostid)1505 void	DBregister_host_flush(zbx_vector_ptr_t *autoreg_hosts, zbx_uint64_t proxy_hostid)
1506 {
1507 	const char		*__function_name = "DBregister_host_flush";
1508 
1509 	zbx_autoreg_host_t	*autoreg_host;
1510 	zbx_uint64_t		autoreg_hostid;
1511 	zbx_db_insert_t		db_insert;
1512 	int			i, create = 0, update = 0;
1513 	char			*sql = NULL, *ip_esc, *dns_esc, *host_metadata_esc;
1514 	size_t			sql_alloc = 256, sql_offset = 0;
1515 	zbx_timespec_t		ts = {0, 0};
1516 
1517 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1518 
1519 	if (SUCCEED != DBregister_host_active())
1520 		goto exit;
1521 
1522 	process_autoreg_hosts(autoreg_hosts, proxy_hostid);
1523 
1524 	for (i = 0; i < autoreg_hosts->values_num; i++)
1525 	{
1526 		autoreg_host = (zbx_autoreg_host_t *)autoreg_hosts->values[i];
1527 
1528 		if (0 == autoreg_host->autoreg_hostid)
1529 			create++;
1530 	}
1531 
1532 	if (0 != create)
1533 	{
1534 		autoreg_hostid = DBget_maxid_num("autoreg_host", create);
1535 
1536 		zbx_db_insert_prepare(&db_insert, "autoreg_host", "autoreg_hostid", "proxy_hostid", "host", "listen_ip",
1537 				"listen_dns", "listen_port", "host_metadata", NULL);
1538 	}
1539 
1540 	if (0 != (update = autoreg_hosts->values_num - create))
1541 	{
1542 		sql = (char *)zbx_malloc(sql, sql_alloc);
1543 		DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
1544 	}
1545 
1546 	zbx_vector_ptr_sort(autoreg_hosts, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1547 
1548 	for (i = 0; i < autoreg_hosts->values_num; i++)
1549 	{
1550 		autoreg_host = (zbx_autoreg_host_t *)autoreg_hosts->values[i];
1551 
1552 		if (0 == autoreg_host->autoreg_hostid)
1553 		{
1554 			autoreg_host->autoreg_hostid = autoreg_hostid++;
1555 
1556 			zbx_db_insert_add_values(&db_insert, autoreg_host->autoreg_hostid, proxy_hostid,
1557 					autoreg_host->host, autoreg_host->ip, autoreg_host->dns,
1558 					(int)autoreg_host->port, autoreg_host->host_metadata);
1559 		}
1560 		else
1561 		{
1562 			ip_esc = DBdyn_escape_string(autoreg_host->ip);
1563 			dns_esc = DBdyn_escape_string(autoreg_host->dns);
1564 			host_metadata_esc = DBdyn_escape_string(autoreg_host->host_metadata);
1565 
1566 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1567 					"update autoreg_host"
1568 					" set listen_ip='%s',"
1569 						"listen_dns='%s',"
1570 						"listen_port=%hu,"
1571 						"host_metadata='%s',"
1572 						"proxy_hostid=%s"
1573 					" where autoreg_hostid=" ZBX_FS_UI64 ";\n",
1574 				ip_esc, dns_esc, autoreg_host->port, host_metadata_esc, DBsql_id_ins(proxy_hostid),
1575 				autoreg_host->autoreg_hostid);
1576 
1577 			zbx_free(host_metadata_esc);
1578 			zbx_free(dns_esc);
1579 			zbx_free(ip_esc);
1580 		}
1581 	}
1582 
1583 	if (0 != create)
1584 	{
1585 		zbx_db_insert_execute(&db_insert);
1586 		zbx_db_insert_clean(&db_insert);
1587 	}
1588 
1589 	if (0 != update)
1590 	{
1591 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
1592 		DBexecute("%s", sql);
1593 		zbx_free(sql);
1594 	}
1595 
1596 	zbx_vector_ptr_sort(autoreg_hosts, compare_autoreg_host_by_hostid);
1597 
1598 	for (i = 0; i < autoreg_hosts->values_num; i++)
1599 	{
1600 		autoreg_host = (zbx_autoreg_host_t *)autoreg_hosts->values[i];
1601 
1602 		ts.sec = autoreg_host->now;
1603 		zbx_add_event(EVENT_SOURCE_AUTOREGISTRATION, EVENT_OBJECT_ZABBIX_ACTIVE, autoreg_host->autoreg_hostid,
1604 				&ts, TRIGGER_VALUE_PROBLEM, NULL, NULL, NULL, 0, 0, NULL, 0, NULL, 0, NULL);
1605 	}
1606 
1607 	zbx_process_events(NULL, NULL);
1608 	zbx_clean_events();
1609 exit:
1610 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1611 }
1612 
DBregister_host_clean(zbx_vector_ptr_t * autoreg_hosts)1613 void	DBregister_host_clean(zbx_vector_ptr_t *autoreg_hosts)
1614 {
1615 	zbx_vector_ptr_clear_ext(autoreg_hosts, (zbx_mem_free_func_t)autoreg_host_free);
1616 }
1617 
1618 /******************************************************************************
1619  *                                                                            *
1620  * Function: DBproxy_register_host                                            *
1621  *                                                                            *
1622  * Purpose: register unknown host                                             *
1623  *                                                                            *
1624  * Parameters: host - host name                                               *
1625  *                                                                            *
1626  * Author: Alexander Vladishev                                                *
1627  *                                                                            *
1628  ******************************************************************************/
DBproxy_register_host(const char * host,const char * ip,const char * dns,unsigned short port,const char * host_metadata)1629 void	DBproxy_register_host(const char *host, const char *ip, const char *dns, unsigned short port,
1630 		const char *host_metadata)
1631 {
1632 	char	*host_esc, *ip_esc, *dns_esc, *host_metadata_esc;
1633 
1634 	host_esc = DBdyn_escape_field("proxy_autoreg_host", "host", host);
1635 	ip_esc = DBdyn_escape_field("proxy_autoreg_host", "listen_ip", ip);
1636 	dns_esc = DBdyn_escape_field("proxy_autoreg_host", "listen_dns", dns);
1637 	host_metadata_esc = DBdyn_escape_field("proxy_autoreg_host", "host_metadata", host_metadata);
1638 
1639 	DBexecute("insert into proxy_autoreg_host"
1640 			" (clock,host,listen_ip,listen_dns,listen_port,host_metadata)"
1641 			" values"
1642 			" (%d,'%s','%s','%s',%d,'%s')",
1643 			(int)time(NULL), host_esc, ip_esc, dns_esc, (int)port, host_metadata_esc);
1644 
1645 	zbx_free(host_metadata_esc);
1646 	zbx_free(dns_esc);
1647 	zbx_free(ip_esc);
1648 	zbx_free(host_esc);
1649 }
1650 
1651 /******************************************************************************
1652  *                                                                            *
1653  * Function: DBexecute_overflowed_sql                                         *
1654  *                                                                            *
1655  * Purpose: execute a set of SQL statements IF it is big enough               *
1656  *                                                                            *
1657  * Author: Dmitry Borovikov                                                   *
1658  *                                                                            *
1659  ******************************************************************************/
DBexecute_overflowed_sql(char ** sql,size_t * sql_alloc,size_t * sql_offset)1660 int	DBexecute_overflowed_sql(char **sql, size_t *sql_alloc, size_t *sql_offset)
1661 {
1662 	int	ret = SUCCEED;
1663 
1664 	if (ZBX_MAX_OVERFLOW_SQL_SIZE < *sql_offset)
1665 	{
1666 #ifdef HAVE_MULTIROW_INSERT
1667 		if (',' == (*sql)[*sql_offset - 1])
1668 		{
1669 			(*sql_offset)--;
1670 			zbx_strcpy_alloc(sql, sql_alloc, sql_offset, ";\n");
1671 		}
1672 #endif
1673 #if defined(HAVE_ORACLE) && 0 == ZBX_MAX_OVERFLOW_SQL_SIZE
1674 		/* make sure we are not called twice without */
1675 		/* putting a new sql into the buffer first */
1676 		if (*sql_offset <= ZBX_SQL_EXEC_FROM)
1677 		{
1678 			THIS_SHOULD_NEVER_HAPPEN;
1679 			return ret;
1680 		}
1681 
1682 		/* Oracle fails with ORA-00911 if it encounters ';' w/o PL/SQL block */
1683 		zbx_rtrim(*sql, ZBX_WHITESPACE ";");
1684 #else
1685 		DBend_multiple_update(sql, sql_alloc, sql_offset);
1686 #endif
1687 		/* For Oracle with max_overflow_sql_size == 0, jump over "begin\n" */
1688 		/* before execution. ZBX_SQL_EXEC_FROM is 0 for all other cases. */
1689 		if (ZBX_DB_OK > DBexecute("%s", *sql + ZBX_SQL_EXEC_FROM))
1690 			ret = FAIL;
1691 
1692 		*sql_offset = 0;
1693 
1694 		DBbegin_multiple_update(sql, sql_alloc, sql_offset);
1695 	}
1696 
1697 	return ret;
1698 }
1699 
1700 /******************************************************************************
1701  *                                                                            *
1702  * Function: DBget_unique_hostname_by_sample                                  *
1703  *                                                                            *
1704  * Purpose: construct a unique host name by the given sample                  *
1705  *                                                                            *
1706  * Parameters: host_name_sample - a host name to start constructing from      *
1707  *                                                                            *
1708  * Return value: unique host name which does not exist in the database        *
1709  *                                                                            *
1710  * Author: Dmitry Borovikov                                                   *
1711  *                                                                            *
1712  * Comments: the sample cannot be empty                                       *
1713  *           constructs new by adding "_$(number+1)", where "number"          *
1714  *           shows count of the sample itself plus already constructed ones   *
1715  *           host_name_sample is not modified, allocates new memory!          *
1716  *                                                                            *
1717  ******************************************************************************/
DBget_unique_hostname_by_sample(const char * host_name_sample)1718 char	*DBget_unique_hostname_by_sample(const char *host_name_sample)
1719 {
1720 	const char		*__function_name = "DBget_unique_hostname_by_sample";
1721 
1722 	DB_RESULT		result;
1723 	DB_ROW			row;
1724 	int			full_match = 0, i;
1725 	char			*host_name_temp = NULL, *host_name_sample_esc;
1726 	zbx_vector_uint64_t	nums;
1727 	zbx_uint64_t		num = 2;	/* produce alternatives starting from "2" */
1728 	size_t			sz;
1729 
1730 	assert(host_name_sample && *host_name_sample);
1731 
1732 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() sample:'%s'", __function_name, host_name_sample);
1733 
1734 	zbx_vector_uint64_create(&nums);
1735 	zbx_vector_uint64_reserve(&nums, 8);
1736 
1737 	sz = strlen(host_name_sample);
1738 	host_name_sample_esc = DBdyn_escape_like_pattern(host_name_sample);
1739 
1740 	result = DBselect(
1741 			"select host"
1742 			" from hosts"
1743 			" where host like '%s%%' escape '%c'"
1744 				" and flags<>%d"
1745 				" and status in (%d,%d,%d)",
1746 			host_name_sample_esc, ZBX_SQL_LIKE_ESCAPE_CHAR,
1747 			ZBX_FLAG_DISCOVERY_PROTOTYPE,
1748 			HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, HOST_STATUS_TEMPLATE);
1749 
1750 	zbx_free(host_name_sample_esc);
1751 
1752 	while (NULL != (row = DBfetch(result)))
1753 	{
1754 		zbx_uint64_t	n;
1755 		const char	*p;
1756 
1757 		if (0 != strncmp(row[0], host_name_sample, sz))
1758 			continue;
1759 
1760 		p = row[0] + sz;
1761 
1762 		if ('\0' == *p)
1763 		{
1764 			full_match = 1;
1765 			continue;
1766 		}
1767 
1768 		if ('_' != *p || FAIL == is_uint64(p + 1, &n))
1769 			continue;
1770 
1771 		zbx_vector_uint64_append(&nums, n);
1772 	}
1773 	DBfree_result(result);
1774 
1775 	zbx_vector_uint64_sort(&nums, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1776 
1777 	if (0 == full_match)
1778 	{
1779 		host_name_temp = zbx_strdup(host_name_temp, host_name_sample);
1780 		goto clean;
1781 	}
1782 
1783 	for (i = 0; i < nums.values_num; i++)
1784 	{
1785 		if (num > nums.values[i])
1786 			continue;
1787 
1788 		if (num < nums.values[i])	/* found, all other will be bigger */
1789 			break;
1790 
1791 		num++;
1792 	}
1793 
1794 	host_name_temp = zbx_dsprintf(host_name_temp, "%s_" ZBX_FS_UI64, host_name_sample, num);
1795 clean:
1796 	zbx_vector_uint64_destroy(&nums);
1797 
1798 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():'%s'", __function_name, host_name_temp);
1799 
1800 	return host_name_temp;
1801 }
1802 
1803 /******************************************************************************
1804  *                                                                            *
1805  * Function: DBsql_id_ins                                                     *
1806  *                                                                            *
1807  * Purpose: construct insert statement                                        *
1808  *                                                                            *
1809  * Return value: "<id>" if id not equal zero,                                 *
1810  *               otherwise "null"                                             *
1811  *                                                                            *
1812  * Author: Alexander Vladishev                                                *
1813  *                                                                            *
1814  ******************************************************************************/
DBsql_id_ins(zbx_uint64_t id)1815 const char	*DBsql_id_ins(zbx_uint64_t id)
1816 {
1817 	static unsigned char	n = 0;
1818 	static char		buf[4][21];	/* 20 - value size, 1 - '\0' */
1819 	static const char	null[5] = "null";
1820 
1821 	if (0 == id)
1822 		return null;
1823 
1824 	n = (n + 1) & 3;
1825 
1826 	zbx_snprintf(buf[n], sizeof(buf[n]), ZBX_FS_UI64, id);
1827 
1828 	return buf[n];
1829 }
1830 
1831 /******************************************************************************
1832  *                                                                            *
1833  * Function: DBget_inventory_field                                            *
1834  *                                                                            *
1835  * Purpose: get corresponding host_inventory field name                       *
1836  *                                                                            *
1837  * Parameters: inventory_link - [IN] field link 1..HOST_INVENTORY_FIELD_COUNT *
1838  *                                                                            *
1839  * Return value: field name or NULL if value of inventory_link is incorrect   *
1840  *                                                                            *
1841  * Author: Alexander Vladishev                                                *
1842  *                                                                            *
1843  ******************************************************************************/
DBget_inventory_field(unsigned char inventory_link)1844 const char	*DBget_inventory_field(unsigned char inventory_link)
1845 {
1846 	static const char	*inventory_fields[HOST_INVENTORY_FIELD_COUNT] =
1847 	{
1848 		"type", "type_full", "name", "alias", "os", "os_full", "os_short", "serialno_a", "serialno_b", "tag",
1849 		"asset_tag", "macaddress_a", "macaddress_b", "hardware", "hardware_full", "software", "software_full",
1850 		"software_app_a", "software_app_b", "software_app_c", "software_app_d", "software_app_e", "contact",
1851 		"location", "location_lat", "location_lon", "notes", "chassis", "model", "hw_arch", "vendor",
1852 		"contract_number", "installer_name", "deployment_status", "url_a", "url_b", "url_c", "host_networks",
1853 		"host_netmask", "host_router", "oob_ip", "oob_netmask", "oob_router", "date_hw_purchase",
1854 		"date_hw_install", "date_hw_expiry", "date_hw_decomm", "site_address_a", "site_address_b",
1855 		"site_address_c", "site_city", "site_state", "site_country", "site_zip", "site_rack", "site_notes",
1856 		"poc_1_name", "poc_1_email", "poc_1_phone_a", "poc_1_phone_b", "poc_1_cell", "poc_1_screen",
1857 		"poc_1_notes", "poc_2_name", "poc_2_email", "poc_2_phone_a", "poc_2_phone_b", "poc_2_cell",
1858 		"poc_2_screen", "poc_2_notes"
1859 	};
1860 
1861 	if (1 > inventory_link || inventory_link > HOST_INVENTORY_FIELD_COUNT)
1862 		return NULL;
1863 
1864 	return inventory_fields[inventory_link - 1];
1865 }
1866 
DBtxn_status(void)1867 int	DBtxn_status(void)
1868 {
1869 	return 0 == zbx_db_txn_error() ? SUCCEED : FAIL;
1870 }
1871 
DBtxn_ongoing(void)1872 int	DBtxn_ongoing(void)
1873 {
1874 	return 0 == zbx_db_txn_level() ? FAIL : SUCCEED;
1875 }
1876 
DBtable_exists(const char * table_name)1877 int	DBtable_exists(const char *table_name)
1878 {
1879 	char		*table_name_esc;
1880 #ifdef HAVE_POSTGRESQL
1881 	char		*table_schema_esc;
1882 #endif
1883 	DB_RESULT	result;
1884 	int		ret;
1885 
1886 	table_name_esc = DBdyn_escape_string(table_name);
1887 
1888 #if defined(HAVE_IBM_DB2)
1889 	/* publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.cmd.doc/doc/r0001967.html */
1890 	result = DBselect(
1891 			"select 1"
1892 			" from syscat.tables"
1893 			" where tabschema=user"
1894 				" and lower(tabname)='%s'",
1895 			table_name_esc);
1896 #elif defined(HAVE_MYSQL)
1897 	result = DBselect("show tables like '%s'", table_name_esc);
1898 #elif defined(HAVE_ORACLE)
1899 	result = DBselect(
1900 			"select 1"
1901 			" from tab"
1902 			" where tabtype='TABLE'"
1903 				" and lower(tname)='%s'",
1904 			table_name_esc);
1905 #elif defined(HAVE_POSTGRESQL)
1906 	table_schema_esc = DBdyn_escape_string(NULL == CONFIG_DBSCHEMA || '\0' == *CONFIG_DBSCHEMA ?
1907 			"public" : CONFIG_DBSCHEMA);
1908 
1909 	result = DBselect(
1910 			"select 1"
1911 			" from information_schema.tables"
1912 			" where table_name='%s'"
1913 				" and table_schema='%s'",
1914 			table_name_esc, table_schema_esc);
1915 
1916 	zbx_free(table_schema_esc);
1917 
1918 #elif defined(HAVE_SQLITE3)
1919 	result = DBselect(
1920 			"select 1"
1921 			" from sqlite_master"
1922 			" where tbl_name='%s'"
1923 				" and type='table'",
1924 			table_name_esc);
1925 #endif
1926 
1927 	zbx_free(table_name_esc);
1928 
1929 	ret = (NULL == DBfetch(result) ? FAIL : SUCCEED);
1930 
1931 	DBfree_result(result);
1932 
1933 	return ret;
1934 }
1935 
DBfield_exists(const char * table_name,const char * field_name)1936 int	DBfield_exists(const char *table_name, const char *field_name)
1937 {
1938 	DB_RESULT	result;
1939 #if defined(HAVE_IBM_DB2)
1940 	char		*table_name_esc, *field_name_esc;
1941 	int		ret;
1942 #elif defined(HAVE_MYSQL)
1943 	char		*field_name_esc;
1944 	int		ret;
1945 #elif defined(HAVE_ORACLE)
1946 	char		*table_name_esc, *field_name_esc;
1947 	int		ret;
1948 #elif defined(HAVE_POSTGRESQL)
1949 	char		*table_name_esc, *field_name_esc, *table_schema_esc;
1950 	int		ret;
1951 #elif defined(HAVE_SQLITE3)
1952 	char		*table_name_esc;
1953 	DB_ROW		row;
1954 	int		ret = FAIL;
1955 #endif
1956 
1957 #if defined(HAVE_IBM_DB2)
1958 	table_name_esc = DBdyn_escape_string(table_name);
1959 	field_name_esc = DBdyn_escape_string(field_name);
1960 
1961 	result = DBselect(
1962 			"select 1"
1963 			" from syscat.columns"
1964 			" where tabschema=user"
1965 				" and lower(tabname)='%s'"
1966 				" and lower(colname)='%s'",
1967 			table_name_esc, field_name_esc);
1968 
1969 	zbx_free(field_name_esc);
1970 	zbx_free(table_name_esc);
1971 
1972 	ret = (NULL == DBfetch(result) ? FAIL : SUCCEED);
1973 
1974 	DBfree_result(result);
1975 #elif defined(HAVE_MYSQL)
1976 	field_name_esc = DBdyn_escape_string(field_name);
1977 
1978 	result = DBselect("show columns from %s like '%s'",
1979 			table_name, field_name_esc);
1980 
1981 	zbx_free(field_name_esc);
1982 
1983 	ret = (NULL == DBfetch(result) ? FAIL : SUCCEED);
1984 
1985 	DBfree_result(result);
1986 #elif defined(HAVE_ORACLE)
1987 	table_name_esc = DBdyn_escape_string(table_name);
1988 	field_name_esc = DBdyn_escape_string(field_name);
1989 
1990 	result = DBselect(
1991 			"select 1"
1992 			" from col"
1993 			" where lower(tname)='%s'"
1994 				" and lower(cname)='%s'",
1995 			table_name_esc, field_name_esc);
1996 
1997 	zbx_free(field_name_esc);
1998 	zbx_free(table_name_esc);
1999 
2000 	ret = (NULL == DBfetch(result) ? FAIL : SUCCEED);
2001 
2002 	DBfree_result(result);
2003 #elif defined(HAVE_POSTGRESQL)
2004 	table_schema_esc = DBdyn_escape_string(NULL == CONFIG_DBSCHEMA || '\0' == *CONFIG_DBSCHEMA ?
2005 			"public" : CONFIG_DBSCHEMA);
2006 	table_name_esc = DBdyn_escape_string(table_name);
2007 	field_name_esc = DBdyn_escape_string(field_name);
2008 
2009 	result = DBselect(
2010 			"select 1"
2011 			" from information_schema.columns"
2012 			" where table_name='%s'"
2013 				" and column_name='%s'"
2014 				" and table_schema='%s'",
2015 			table_name_esc, field_name_esc, table_schema_esc);
2016 
2017 	zbx_free(field_name_esc);
2018 	zbx_free(table_name_esc);
2019 	zbx_free(table_schema_esc);
2020 
2021 	ret = (NULL == DBfetch(result) ? FAIL : SUCCEED);
2022 
2023 	DBfree_result(result);
2024 #elif defined(HAVE_SQLITE3)
2025 	table_name_esc = DBdyn_escape_string(table_name);
2026 
2027 	result = DBselect("PRAGMA table_info('%s')", table_name_esc);
2028 
2029 	zbx_free(table_name_esc);
2030 
2031 	while (NULL != (row = DBfetch(result)))
2032 	{
2033 		if (0 != strcmp(field_name, row[1]))
2034 			continue;
2035 
2036 		ret = SUCCEED;
2037 		break;
2038 	}
2039 	DBfree_result(result);
2040 #endif
2041 
2042 	return ret;
2043 }
2044 
2045 #ifndef HAVE_SQLITE3
DBindex_exists(const char * table_name,const char * index_name)2046 int	DBindex_exists(const char *table_name, const char *index_name)
2047 {
2048 	char		*table_name_esc, *index_name_esc;
2049 #if defined(HAVE_POSTGRESQL)
2050 	char		*table_schema_esc;
2051 #endif
2052 	DB_RESULT	result;
2053 	int		ret;
2054 
2055 	table_name_esc = DBdyn_escape_string(table_name);
2056 	index_name_esc = DBdyn_escape_string(index_name);
2057 
2058 #if defined(HAVE_IBM_DB2)
2059 	result = DBselect(
2060 			"select 1"
2061 			" from syscat.indexes"
2062 			" where tabschema=user"
2063 				" and lower(tabname)='%s'"
2064 				" and lower(indname)='%s'",
2065 			table_name_esc, index_name_esc);
2066 #elif defined(HAVE_MYSQL)
2067 	result = DBselect(
2068 			"show index from %s"
2069 			" where key_name='%s'",
2070 			table_name_esc, index_name_esc);
2071 #elif defined(HAVE_ORACLE)
2072 	result = DBselect(
2073 			"select 1"
2074 			" from user_indexes"
2075 			" where lower(table_name)='%s'"
2076 				" and lower(index_name)='%s'",
2077 			table_name_esc, index_name_esc);
2078 #elif defined(HAVE_POSTGRESQL)
2079 	table_schema_esc = DBdyn_escape_string(NULL == CONFIG_DBSCHEMA || '\0' == *CONFIG_DBSCHEMA ?
2080 				"public" : CONFIG_DBSCHEMA);
2081 
2082 	result = DBselect(
2083 			"select 1"
2084 			" from pg_indexes"
2085 			" where tablename='%s'"
2086 				" and indexname='%s'"
2087 				" and schemaname='%s'",
2088 			table_name_esc, index_name_esc, table_schema_esc);
2089 
2090 	zbx_free(table_schema_esc);
2091 #endif
2092 
2093 	ret = (NULL == DBfetch(result) ? FAIL : SUCCEED);
2094 
2095 	DBfree_result(result);
2096 
2097 	zbx_free(table_name_esc);
2098 	zbx_free(index_name_esc);
2099 
2100 	return ret;
2101 }
2102 #endif
2103 
2104 /******************************************************************************
2105  *                                                                            *
2106  * Function: DBselect_uint64                                                  *
2107  *                                                                            *
2108  * Parameters: sql - [IN] sql statement                                       *
2109  *             ids - [OUT] sorted list of selected uint64 values              *
2110  *                                                                            *
2111  ******************************************************************************/
DBselect_uint64(const char * sql,zbx_vector_uint64_t * ids)2112 void	DBselect_uint64(const char *sql, zbx_vector_uint64_t *ids)
2113 {
2114 	DB_RESULT	result;
2115 	DB_ROW		row;
2116 	zbx_uint64_t	id;
2117 
2118 	result = DBselect("%s", sql);
2119 
2120 	while (NULL != (row = DBfetch(result)))
2121 	{
2122 		ZBX_STR2UINT64(id, row[0]);
2123 
2124 		zbx_vector_uint64_append(ids, id);
2125 	}
2126 	DBfree_result(result);
2127 
2128 	zbx_vector_uint64_sort(ids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2129 }
2130 
DBexecute_multiple_query(const char * query,const char * field_name,zbx_vector_uint64_t * ids)2131 int	DBexecute_multiple_query(const char *query, const char *field_name, zbx_vector_uint64_t *ids)
2132 {
2133 #define ZBX_MAX_IDS	950
2134 	char	*sql = NULL;
2135 	size_t	sql_alloc = ZBX_KIBIBYTE, sql_offset = 0;
2136 	int	i, ret = SUCCEED;
2137 
2138 	sql = (char *)zbx_malloc(sql, sql_alloc);
2139 
2140 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
2141 
2142 	for (i = 0; i < ids->values_num; i += ZBX_MAX_IDS)
2143 	{
2144 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, query);
2145 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, field_name,
2146 				&ids->values[i], MIN(ZBX_MAX_IDS, ids->values_num - i));
2147 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2148 
2149 		if (SUCCEED != (ret = DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset)))
2150 			break;
2151 	}
2152 
2153 	if (SUCCEED == ret && sql_offset > 16)	/* in ORACLE always present begin..end; */
2154 	{
2155 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
2156 
2157 		if (ZBX_DB_OK > DBexecute("%s", sql))
2158 			ret = FAIL;
2159 	}
2160 
2161 	zbx_free(sql);
2162 
2163 	return ret;
2164 }
2165 
2166 #if defined(HAVE_MYSQL) || defined(HAVE_POSTGRESQL)
zbx_warn_char_set(const char * db_name,const char * char_set)2167 static void	zbx_warn_char_set(const char *db_name, const char *char_set)
2168 {
2169 	zabbix_log(LOG_LEVEL_WARNING, "Zabbix supports only \"" ZBX_SUPPORTED_DB_CHARACTER_SET "\" character set."
2170 			" Database \"%s\" has default character set \"%s\"", db_name, char_set);
2171 }
2172 #endif
2173 
2174 #if defined(HAVE_MYSQL) || defined(HAVE_POSTGRESQL) || defined(HAVE_ORACLE)
zbx_warn_no_charset_info(const char * db_name)2175 static void	zbx_warn_no_charset_info(const char *db_name)
2176 {
2177 	zabbix_log(LOG_LEVEL_WARNING, "Cannot get database \"%s\" character set", db_name);
2178 }
2179 #endif
2180 
DBcheck_character_set(void)2181 void	DBcheck_character_set(void)
2182 {
2183 #if defined(HAVE_MYSQL)
2184 	char		*database_name_esc;
2185 	DB_RESULT	result;
2186 	DB_ROW		row;
2187 
2188 	database_name_esc = DBdyn_escape_string(CONFIG_DBNAME);
2189 	DBconnect(ZBX_DB_CONNECT_NORMAL);
2190 
2191 	result = DBselect(
2192 			"select default_character_set_name,default_collation_name"
2193 			" from information_schema.SCHEMATA"
2194 			" where schema_name='%s'", database_name_esc);
2195 
2196 	if (NULL == result || NULL == (row = DBfetch(result)))
2197 	{
2198 		zbx_warn_no_charset_info(CONFIG_DBNAME);
2199 	}
2200 	else
2201 	{
2202 		char	*char_set = row[0];
2203 		char	*collation = row[1];
2204 
2205 		if (0 != strcasecmp(char_set, ZBX_SUPPORTED_DB_CHARACTER_SET))
2206 			zbx_warn_char_set(CONFIG_DBNAME, char_set);
2207 
2208 		if (0 != zbx_strncasecmp(collation, ZBX_SUPPORTED_DB_COLLATION, sizeof(ZBX_SUPPORTED_DB_COLLATION)))
2209 		{
2210 			zabbix_log(LOG_LEVEL_WARNING, "Zabbix supports only \"%s\" collation."
2211 					" Database \"%s\" has default collation \"%s\"", ZBX_SUPPORTED_DB_COLLATION,
2212 					CONFIG_DBNAME, collation);
2213 		}
2214 	}
2215 
2216 	DBfree_result(result);
2217 
2218 	result = DBselect(
2219 			"select count(*)"
2220 			" from information_schema.`COLUMNS`"
2221 			" where table_schema='%s'"
2222 				" and data_type in ('text','varchar','longtext')"
2223 				" and (character_set_name<>'%s' or collation_name<>'%s')",
2224 			database_name_esc, ZBX_SUPPORTED_DB_CHARACTER_SET, ZBX_SUPPORTED_DB_COLLATION);
2225 
2226 	if (NULL == result || NULL == (row = DBfetch(result)))
2227 	{
2228 		zabbix_log(LOG_LEVEL_WARNING, "cannot get character set of database \"%s\" tables", CONFIG_DBNAME);
2229 	}
2230 	else if (0 != strcmp("0", row[0]))
2231 	{
2232 		zabbix_log(LOG_LEVEL_WARNING, "character set name or collation name that is not supported by Zabbix"
2233 				" found in %s column(s) of database \"%s\"", row[0], CONFIG_DBNAME);
2234 		zabbix_log(LOG_LEVEL_WARNING, "only character set \"%s\" and collation \"%s\" should be used in "
2235 				"database", ZBX_SUPPORTED_DB_CHARACTER_SET, ZBX_SUPPORTED_DB_COLLATION);
2236 	}
2237 
2238 	DBfree_result(result);
2239 	DBclose();
2240 	zbx_free(database_name_esc);
2241 #elif defined(HAVE_ORACLE)
2242 	DB_RESULT	result;
2243 	DB_ROW		row;
2244 
2245 	DBconnect(ZBX_DB_CONNECT_NORMAL);
2246 	result = DBselect(
2247 			"select parameter,value"
2248 			" from NLS_DATABASE_PARAMETERS"
2249 			" where parameter in ('NLS_CHARACTERSET','NLS_NCHAR_CHARACTERSET')");
2250 
2251 	if (NULL == result)
2252 	{
2253 		zbx_warn_no_charset_info(CONFIG_DBNAME);
2254 	}
2255 	else
2256 	{
2257 		while (NULL != (row = DBfetch(result)))
2258 		{
2259 			const char	*parameter = row[0];
2260 			const char	*value = row[1];
2261 
2262 			if (NULL == parameter || NULL == value)
2263 			{
2264 				continue;
2265 			}
2266 			else if (0 == strcasecmp("NLS_CHARACTERSET", parameter) ||
2267 					(0 == strcasecmp("NLS_NCHAR_CHARACTERSET", parameter)))
2268 			{
2269 				if (0 != strcasecmp(ZBX_SUPPORTED_DB_CHARACTER_SET, value))
2270 				{
2271 					zabbix_log(LOG_LEVEL_WARNING, "database \"%s\" parameter \"%s\" has value"
2272 							" \"%s\". Zabbix supports only \"%s\" character set",
2273 							CONFIG_DBNAME, parameter, value,
2274 							ZBX_SUPPORTED_DB_CHARACTER_SET);
2275 				}
2276 			}
2277 		}
2278 	}
2279 
2280 	DBfree_result(result);
2281 	DBclose();
2282 #elif defined(HAVE_POSTGRESQL)
2283 #define OID_LENGTH_MAX		20
2284 
2285 	char		*database_name_esc, *schema_name_esc, oid[OID_LENGTH_MAX];
2286 	DB_RESULT	result;
2287 	DB_ROW		row;
2288 
2289 	database_name_esc = DBdyn_escape_string(CONFIG_DBNAME);
2290 	schema_name_esc = (NULL != CONFIG_DBSCHEMA) ? DBdyn_escape_string(CONFIG_DBSCHEMA) : strdup("public");
2291 
2292 	DBconnect(ZBX_DB_CONNECT_NORMAL);
2293 	result = DBselect(
2294 			"select pg_encoding_to_char(encoding)"
2295 			" from pg_database"
2296 			" where datname='%s'",
2297 			database_name_esc);
2298 
2299 	if (NULL == result || NULL == (row = DBfetch(result)))
2300 	{
2301 		zbx_warn_no_charset_info(CONFIG_DBNAME);
2302 		goto out;
2303 	}
2304 	else if (strcasecmp(row[0], ZBX_SUPPORTED_DB_CHARACTER_SET))
2305 	{
2306 		zbx_warn_char_set(CONFIG_DBNAME, row[0]);
2307 		goto out;
2308 
2309 	}
2310 
2311 	DBfree_result(result);
2312 
2313 	result = DBselect(
2314 			"select oid"
2315 			" from pg_namespace"
2316 			" where nspname='%s'",
2317 			schema_name_esc);
2318 
2319 	if (NULL == result || NULL == (row = DBfetch(result)) || '\0' == **row)
2320 	{
2321 		zabbix_log(LOG_LEVEL_WARNING, "cannot get character set of database \"%s\" fields", CONFIG_DBNAME);
2322 		goto out;
2323 	}
2324 
2325 	strscpy(oid, *row);
2326 
2327 	DBfree_result(result);
2328 
2329 	result = DBselect(
2330 			"select count(*)"
2331 			" from pg_attribute as a"
2332 				" left join pg_class as c"
2333 					" on c.relfilenode=a.attrelid"
2334 				" left join pg_collation as l"
2335 					" on l.oid=a.attcollation"
2336 			" where atttypid in (25,1043)"
2337 				" and c.relnamespace=%s"
2338 				" and c.relam=0"
2339 				" and l.collname<>'default'",
2340 			oid);
2341 
2342 	if (NULL == result || NULL == (row = DBfetch(result)))
2343 	{
2344 		zabbix_log(LOG_LEVEL_WARNING, "cannot get character set of database \"%s\" fields", CONFIG_DBNAME);
2345 	}
2346 	else if (0 != strcmp("0", row[0]))
2347 	{
2348 		zabbix_log(LOG_LEVEL_WARNING, "database has %s fields with unsupported character set. Zabbix supports"
2349 				" only \"%s\" character set", row[0], ZBX_SUPPORTED_DB_CHARACTER_SET);
2350 	}
2351 
2352 	DBfree_result(result);
2353 
2354 	result = DBselect("show client_encoding");
2355 
2356 	if (NULL == result || NULL == (row = DBfetch(result)))
2357 	{
2358 		zabbix_log(LOG_LEVEL_WARNING, "cannot get info about database \"%s\" client encoding", CONFIG_DBNAME);
2359 	}
2360 	else if (0 != strcasecmp(row[0], ZBX_SUPPORTED_DB_CHARACTER_SET))
2361 	{
2362 		zabbix_log(LOG_LEVEL_WARNING, "client_encoding for database \"%s\" is \"%s\". Zabbix supports only"
2363 				" \"%s\"", CONFIG_DBNAME, row[0], ZBX_SUPPORTED_DB_CHARACTER_SET);
2364 	}
2365 
2366 	DBfree_result(result);
2367 
2368 	result = DBselect("show server_encoding");
2369 
2370 	if (NULL == result || NULL == (row = DBfetch(result)))
2371 	{
2372 		zabbix_log(LOG_LEVEL_WARNING, "cannot get info about database \"%s\" server encoding", CONFIG_DBNAME);
2373 	}
2374 	else if (0 != strcasecmp(row[0], ZBX_SUPPORTED_DB_CHARACTER_SET))
2375 	{
2376 		zabbix_log(LOG_LEVEL_WARNING, "server_encoding for database \"%s\" is \"%s\". Zabbix supports only"
2377 				" \"%s\"", CONFIG_DBNAME, row[0], ZBX_SUPPORTED_DB_CHARACTER_SET);
2378 	}
2379 out:
2380 	DBfree_result(result);
2381 	DBclose();
2382 	zbx_free(schema_name_esc);
2383 	zbx_free(database_name_esc);
2384 #endif
2385 }
2386 
2387 #ifdef HAVE_ORACLE
2388 /******************************************************************************
2389  *                                                                            *
2390  * Function: zbx_db_format_values                                             *
2391  *                                                                            *
2392  * Purpose: format bulk operation (insert, update) value list                 *
2393  *                                                                            *
2394  * Parameters: fields     - [IN] the field list                               *
2395  *             values     - [IN] the corresponding value list                 *
2396  *             values_num - [IN] the number of values to format               *
2397  *                                                                            *
2398  * Return value: the formatted value list <value1>,<value2>...                *
2399  *                                                                            *
2400  * Comments: The returned string is allocated by this function and must be    *
2401  *           freed by the caller later.                                       *
2402  *                                                                            *
2403  ******************************************************************************/
zbx_db_format_values(ZBX_FIELD ** fields,const zbx_db_value_t * values,int values_num)2404 static char	*zbx_db_format_values(ZBX_FIELD **fields, const zbx_db_value_t *values, int values_num)
2405 {
2406 	int	i;
2407 	char	*str = NULL;
2408 	size_t	str_alloc = 0, str_offset = 0;
2409 
2410 	for (i = 0; i < values_num; i++)
2411 	{
2412 		ZBX_FIELD		*field = fields[i];
2413 		const zbx_db_value_t	*value = &values[i];
2414 
2415 		if (0 < i)
2416 			zbx_chrcpy_alloc(&str, &str_alloc, &str_offset, ',');
2417 
2418 		switch (field->type)
2419 		{
2420 			case ZBX_TYPE_CHAR:
2421 			case ZBX_TYPE_TEXT:
2422 			case ZBX_TYPE_SHORTTEXT:
2423 			case ZBX_TYPE_LONGTEXT:
2424 				zbx_snprintf_alloc(&str, &str_alloc, &str_offset, "'%s'", value->str);
2425 				break;
2426 			case ZBX_TYPE_FLOAT:
2427 				zbx_snprintf_alloc(&str, &str_alloc, &str_offset, ZBX_FS_DBL, value->dbl);
2428 				break;
2429 			case ZBX_TYPE_ID:
2430 			case ZBX_TYPE_UINT:
2431 				zbx_snprintf_alloc(&str, &str_alloc, &str_offset, ZBX_FS_UI64, value->ui64);
2432 				break;
2433 			case ZBX_TYPE_INT:
2434 				zbx_snprintf_alloc(&str, &str_alloc, &str_offset, "%d", value->i32);
2435 				break;
2436 			default:
2437 				zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "(unknown type)");
2438 				break;
2439 		}
2440 	}
2441 
2442 	return str;
2443 }
2444 #endif
2445 
2446 /******************************************************************************
2447  *                                                                            *
2448  * Function: zbx_db_insert_clean                                              *
2449  *                                                                            *
2450  * Purpose: releases resources allocated by bulk insert operations            *
2451  *                                                                            *
2452  * Parameters: self        - [IN] the bulk insert data                        *
2453  *                                                                            *
2454  ******************************************************************************/
zbx_db_insert_clean(zbx_db_insert_t * self)2455 void	zbx_db_insert_clean(zbx_db_insert_t *self)
2456 {
2457 	int	i, j;
2458 
2459 	for (i = 0; i < self->rows.values_num; i++)
2460 	{
2461 		zbx_db_value_t	*row = (zbx_db_value_t *)self->rows.values[i];
2462 
2463 		for (j = 0; j < self->fields.values_num; j++)
2464 		{
2465 			ZBX_FIELD	*field = (ZBX_FIELD *)self->fields.values[j];
2466 
2467 			switch (field->type)
2468 			{
2469 				case ZBX_TYPE_CHAR:
2470 				case ZBX_TYPE_TEXT:
2471 				case ZBX_TYPE_SHORTTEXT:
2472 				case ZBX_TYPE_LONGTEXT:
2473 					zbx_free(row[j].str);
2474 			}
2475 		}
2476 
2477 		zbx_free(row);
2478 	}
2479 
2480 	zbx_vector_ptr_destroy(&self->rows);
2481 
2482 	zbx_vector_ptr_destroy(&self->fields);
2483 }
2484 
2485 /******************************************************************************
2486  *                                                                            *
2487  * Function: zbx_db_insert_prepare_dyn                                        *
2488  *                                                                            *
2489  * Purpose: prepare for database bulk insert operation                        *
2490  *                                                                            *
2491  * Parameters: self        - [IN] the bulk insert data                        *
2492  *             table       - [IN] the target table name                       *
2493  *             fields      - [IN] names of the fields to insert               *
2494  *             fields_num  - [IN] the number of items in fields array         *
2495  *                                                                            *
2496  * Comments: The operation fails if the target table does not have the        *
2497  *           specified fields defined in its schema.                          *
2498  *                                                                            *
2499  *           Usage example:                                                   *
2500  *             zbx_db_insert_t ins;                                           *
2501  *                                                                            *
2502  *             zbx_db_insert_prepare(&ins, "history", "id", "value");         *
2503  *             zbx_db_insert_add_values(&ins, (zbx_uint64_t)1, 1.0);          *
2504  *             zbx_db_insert_add_values(&ins, (zbx_uint64_t)2, 2.0);          *
2505  *               ...                                                          *
2506  *             zbx_db_insert_execute(&ins);                                   *
2507  *             zbx_db_insert_clean(&ins);                                     *
2508  *                                                                            *
2509  ******************************************************************************/
zbx_db_insert_prepare_dyn(zbx_db_insert_t * self,const ZBX_TABLE * table,const ZBX_FIELD ** fields,int fields_num)2510 void	zbx_db_insert_prepare_dyn(zbx_db_insert_t *self, const ZBX_TABLE *table, const ZBX_FIELD **fields, int fields_num)
2511 {
2512 	int	i;
2513 
2514 	if (0 == fields_num)
2515 	{
2516 		THIS_SHOULD_NEVER_HAPPEN;
2517 		exit(EXIT_FAILURE);
2518 	}
2519 
2520 	self->autoincrement = -1;
2521 
2522 	zbx_vector_ptr_create(&self->fields);
2523 	zbx_vector_ptr_create(&self->rows);
2524 
2525 	self->table = table;
2526 
2527 	for (i = 0; i < fields_num; i++)
2528 		zbx_vector_ptr_append(&self->fields, (ZBX_FIELD *)fields[i]);
2529 }
2530 
2531 /******************************************************************************
2532  *                                                                            *
2533  * Function: zbx_db_insert_prepare                                            *
2534  *                                                                            *
2535  * Purpose: prepare for database bulk insert operation                        *
2536  *                                                                            *
2537  * Parameters: self  - [IN] the bulk insert data                              *
2538  *             table - [IN] the target table name                             *
2539  *             ...   - [IN] names of the fields to insert                     *
2540  *             NULL  - [IN] terminating NULL pointer                          *
2541  *                                                                            *
2542  * Comments: This is a convenience wrapper for zbx_db_insert_prepare_dyn()    *
2543  *           function.                                                        *
2544  *                                                                            *
2545  ******************************************************************************/
zbx_db_insert_prepare(zbx_db_insert_t * self,const char * table,...)2546 void	zbx_db_insert_prepare(zbx_db_insert_t *self, const char *table, ...)
2547 {
2548 	zbx_vector_ptr_t	fields;
2549 	va_list			args;
2550 	char			*field;
2551 	const ZBX_TABLE		*ptable;
2552 	const ZBX_FIELD		*pfield;
2553 
2554 	/* find the table and fields in database schema */
2555 	if (NULL == (ptable = DBget_table(table)))
2556 	{
2557 		THIS_SHOULD_NEVER_HAPPEN;
2558 		exit(EXIT_FAILURE);
2559 	}
2560 
2561 	va_start(args, table);
2562 
2563 	zbx_vector_ptr_create(&fields);
2564 
2565 	while (NULL != (field = va_arg(args, char *)))
2566 	{
2567 		if (NULL == (pfield = DBget_field(ptable, field)))
2568 		{
2569 			zabbix_log(LOG_LEVEL_ERR, "Cannot locate table \"%s\" field \"%s\" in database schema",
2570 					table, field);
2571 			THIS_SHOULD_NEVER_HAPPEN;
2572 			exit(EXIT_FAILURE);
2573 		}
2574 		zbx_vector_ptr_append(&fields, (ZBX_FIELD *)pfield);
2575 	}
2576 
2577 	va_end(args);
2578 
2579 	zbx_db_insert_prepare_dyn(self, ptable, (const ZBX_FIELD **)fields.values, fields.values_num);
2580 
2581 	zbx_vector_ptr_destroy(&fields);
2582 }
2583 
2584 /******************************************************************************
2585  *                                                                            *
2586  * Function: zbx_db_insert_add_values_dyn                                     *
2587  *                                                                            *
2588  * Purpose: adds row values for database bulk insert operation                *
2589  *                                                                            *
2590  * Parameters: self        - [IN] the bulk insert data                        *
2591  *             values      - [IN] the values to insert                        *
2592  *             fields_num  - [IN] the number of items in values array         *
2593  *                                                                            *
2594  * Comments: The values must be listed in the same order as the field names   *
2595  *           for insert preparation functions.                                *
2596  *                                                                            *
2597  ******************************************************************************/
zbx_db_insert_add_values_dyn(zbx_db_insert_t * self,const zbx_db_value_t ** values,int values_num)2598 void	zbx_db_insert_add_values_dyn(zbx_db_insert_t *self, const zbx_db_value_t **values, int values_num)
2599 {
2600 	int		i;
2601 	zbx_db_value_t	*row;
2602 
2603 	if (values_num != self->fields.values_num)
2604 	{
2605 		THIS_SHOULD_NEVER_HAPPEN;
2606 		exit(EXIT_FAILURE);
2607 	}
2608 
2609 	row = (zbx_db_value_t *)zbx_malloc(NULL, self->fields.values_num * sizeof(zbx_db_value_t));
2610 
2611 	for (i = 0; i < self->fields.values_num; i++)
2612 	{
2613 		ZBX_FIELD		*field = (ZBX_FIELD *)self->fields.values[i];
2614 		const zbx_db_value_t	*value = values[i];
2615 
2616 		switch (field->type)
2617 		{
2618 			case ZBX_TYPE_LONGTEXT:
2619 			case ZBX_TYPE_CHAR:
2620 			case ZBX_TYPE_TEXT:
2621 			case ZBX_TYPE_SHORTTEXT:
2622 #ifdef HAVE_ORACLE
2623 				row[i].str = DBdyn_escape_field_len(field, value->str, ESCAPE_SEQUENCE_OFF);
2624 #else
2625 				row[i].str = DBdyn_escape_field_len(field, value->str, ESCAPE_SEQUENCE_ON);
2626 #endif
2627 				break;
2628 			default:
2629 				row[i] = *value;
2630 				break;
2631 		}
2632 	}
2633 
2634 	zbx_vector_ptr_append(&self->rows, row);
2635 }
2636 
2637 /******************************************************************************
2638  *                                                                            *
2639  * Function: zbx_db_insert_add_values                                         *
2640  *                                                                            *
2641  * Purpose: adds row values for database bulk insert operation                *
2642  *                                                                            *
2643  * Parameters: self - [IN] the bulk insert data                               *
2644  *             ...  - [IN] the values to insert                               *
2645  *                                                                            *
2646  * Comments: This is a convenience wrapper for zbx_db_insert_add_values_dyn() *
2647  *           function.                                                        *
2648  *           Note that the types of the passed values must conform to the     *
2649  *           corresponding field types.                                       *
2650  *                                                                            *
2651  ******************************************************************************/
zbx_db_insert_add_values(zbx_db_insert_t * self,...)2652 void	zbx_db_insert_add_values(zbx_db_insert_t *self, ...)
2653 {
2654 	zbx_vector_ptr_t	values;
2655 	va_list			args;
2656 	int			i;
2657 	ZBX_FIELD		*field;
2658 	zbx_db_value_t		*value;
2659 
2660 	va_start(args, self);
2661 
2662 	zbx_vector_ptr_create(&values);
2663 
2664 	for (i = 0; i < self->fields.values_num; i++)
2665 	{
2666 		field = (ZBX_FIELD *)self->fields.values[i];
2667 
2668 		value = (zbx_db_value_t *)zbx_malloc(NULL, sizeof(zbx_db_value_t));
2669 
2670 		switch (field->type)
2671 		{
2672 			case ZBX_TYPE_CHAR:
2673 			case ZBX_TYPE_TEXT:
2674 			case ZBX_TYPE_SHORTTEXT:
2675 			case ZBX_TYPE_LONGTEXT:
2676 				value->str = va_arg(args, char *);
2677 				break;
2678 			case ZBX_TYPE_INT:
2679 				value->i32 = va_arg(args, int);
2680 				break;
2681 			case ZBX_TYPE_FLOAT:
2682 				value->dbl = va_arg(args, double);
2683 				break;
2684 			case ZBX_TYPE_UINT:
2685 			case ZBX_TYPE_ID:
2686 				value->ui64 = va_arg(args, zbx_uint64_t);
2687 				break;
2688 			default:
2689 				THIS_SHOULD_NEVER_HAPPEN;
2690 				exit(EXIT_FAILURE);
2691 		}
2692 
2693 		zbx_vector_ptr_append(&values, value);
2694 	}
2695 
2696 	va_end(args);
2697 
2698 	zbx_db_insert_add_values_dyn(self, (const zbx_db_value_t **)values.values, values.values_num);
2699 
2700 	zbx_vector_ptr_clear_ext(&values, zbx_ptr_free);
2701 	zbx_vector_ptr_destroy(&values);
2702 }
2703 
2704 /******************************************************************************
2705  *                                                                            *
2706  * Function: zbx_db_insert_execute                                            *
2707  *                                                                            *
2708  * Purpose: executes the prepared database bulk insert operation              *
2709  *                                                                            *
2710  * Parameters: self - [IN] the bulk insert data                               *
2711  *                                                                            *
2712  * Return value: Returns SUCCEED if the operation completed successfully or   *
2713  *               FAIL otherwise.                                              *
2714  *                                                                            *
2715  ******************************************************************************/
zbx_db_insert_execute(zbx_db_insert_t * self)2716 int	zbx_db_insert_execute(zbx_db_insert_t *self)
2717 {
2718 	int		ret = FAIL, i, j;
2719 	const ZBX_FIELD	*field;
2720 	char		*sql_command, delim[2] = {',', '('};
2721 	size_t		sql_command_alloc = 512, sql_command_offset = 0;
2722 
2723 #ifndef HAVE_ORACLE
2724 	char		*sql;
2725 	size_t		sql_alloc = 16 * ZBX_KIBIBYTE, sql_offset = 0;
2726 
2727 #	ifdef HAVE_MYSQL
2728 	char		*sql_values = NULL;
2729 	size_t		sql_values_alloc = 0, sql_values_offset = 0;
2730 #	endif
2731 #else
2732 	zbx_db_bind_context_t	*contexts;
2733 	int			rc, tries = 0;
2734 #endif
2735 
2736 	if (0 == self->rows.values_num)
2737 		return SUCCEED;
2738 
2739 	/* process the auto increment field */
2740 	if (-1 != self->autoincrement)
2741 	{
2742 		zbx_uint64_t	id;
2743 
2744 		id = DBget_maxid_num(self->table->table, self->rows.values_num);
2745 
2746 		for (i = 0; i < self->rows.values_num; i++)
2747 		{
2748 			zbx_db_value_t	*values = (zbx_db_value_t *)self->rows.values[i];
2749 
2750 			values[self->autoincrement].ui64 = id++;
2751 		}
2752 	}
2753 
2754 #ifndef HAVE_ORACLE
2755 	sql = (char *)zbx_malloc(NULL, sql_alloc);
2756 #endif
2757 	sql_command = (char *)zbx_malloc(NULL, sql_command_alloc);
2758 
2759 	/* create sql insert statement command */
2760 
2761 	zbx_strcpy_alloc(&sql_command, &sql_command_alloc, &sql_command_offset, "insert into ");
2762 	zbx_strcpy_alloc(&sql_command, &sql_command_alloc, &sql_command_offset, self->table->table);
2763 	zbx_chrcpy_alloc(&sql_command, &sql_command_alloc, &sql_command_offset, ' ');
2764 
2765 	for (i = 0; i < self->fields.values_num; i++)
2766 	{
2767 		field = (ZBX_FIELD *)self->fields.values[i];
2768 
2769 		zbx_chrcpy_alloc(&sql_command, &sql_command_alloc, &sql_command_offset, delim[0 == i]);
2770 		zbx_strcpy_alloc(&sql_command, &sql_command_alloc, &sql_command_offset, field->name);
2771 	}
2772 
2773 #ifdef HAVE_MYSQL
2774 	/* MySQL workaround - explicitly add missing text fields with '' default value */
2775 	for (field = (const ZBX_FIELD *)self->table->fields; NULL != field->name; field++)
2776 	{
2777 		switch (field->type)
2778 		{
2779 			case ZBX_TYPE_BLOB:
2780 			case ZBX_TYPE_TEXT:
2781 			case ZBX_TYPE_SHORTTEXT:
2782 			case ZBX_TYPE_LONGTEXT:
2783 				if (FAIL != zbx_vector_ptr_search(&self->fields, (void *)field,
2784 						ZBX_DEFAULT_PTR_COMPARE_FUNC))
2785 				{
2786 					continue;
2787 				}
2788 
2789 				zbx_chrcpy_alloc(&sql_command, &sql_command_alloc, &sql_command_offset, ',');
2790 				zbx_strcpy_alloc(&sql_command, &sql_command_alloc, &sql_command_offset, field->name);
2791 
2792 				zbx_strcpy_alloc(&sql_values, &sql_values_alloc, &sql_values_offset, ",''");
2793 				break;
2794 		}
2795 	}
2796 #endif
2797 	zbx_strcpy_alloc(&sql_command, &sql_command_alloc, &sql_command_offset, ") values ");
2798 
2799 #ifdef HAVE_ORACLE
2800 	for (i = 0; i < self->fields.values_num; i++)
2801 	{
2802 		zbx_chrcpy_alloc(&sql_command, &sql_command_alloc, &sql_command_offset, delim[0 == i]);
2803 		zbx_snprintf_alloc(&sql_command, &sql_command_alloc, &sql_command_offset, ":%d", i + 1);
2804 	}
2805 	zbx_chrcpy_alloc(&sql_command, &sql_command_alloc, &sql_command_offset, ')');
2806 
2807 	contexts = (zbx_db_bind_context_t *)zbx_malloc(NULL, sizeof(zbx_db_bind_context_t) * self->fields.values_num);
2808 
2809 retry_oracle:
2810 	DBstatement_prepare(sql_command);
2811 
2812 	for (j = 0; j < self->fields.values_num; j++)
2813 	{
2814 		field = (ZBX_FIELD *)self->fields.values[j];
2815 
2816 		if (ZBX_DB_OK > zbx_db_bind_parameter_dyn(&contexts[j], j, field->type,
2817 				(zbx_db_value_t **)self->rows.values, self->rows.values_num))
2818 		{
2819 			for (i = 0; i < j; i++)
2820 				zbx_db_clean_bind_context(&contexts[i]);
2821 
2822 			goto out;
2823 		}
2824 	}
2825 
2826 	if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
2827 	{
2828 		for (i = 0; i < self->rows.values_num; i++)
2829 		{
2830 			zbx_db_value_t	*values = (zbx_db_value_t *)self->rows.values[i];
2831 			char	*str;
2832 
2833 			str = zbx_db_format_values((ZBX_FIELD **)self->fields.values, values, self->fields.values_num);
2834 			zabbix_log(LOG_LEVEL_DEBUG, "insert [txnlev:%d] [%s]", zbx_db_txn_level(), str);
2835 			zbx_free(str);
2836 		}
2837 	}
2838 
2839 	rc = zbx_db_statement_execute(self->rows.values_num);
2840 
2841 	for (j = 0; j < self->fields.values_num; j++)
2842 		zbx_db_clean_bind_context(&contexts[j]);
2843 
2844 	if (ZBX_DB_DOWN == rc)
2845 	{
2846 		if (0 < tries++)
2847 		{
2848 			zabbix_log(LOG_LEVEL_ERR, "database is down: retrying in %d seconds", ZBX_DB_WAIT_DOWN);
2849 			connection_failure = 1;
2850 			sleep(ZBX_DB_WAIT_DOWN);
2851 		}
2852 
2853 		DBclose();
2854 		DBconnect(ZBX_DB_CONNECT_NORMAL);
2855 
2856 		goto retry_oracle;
2857 	}
2858 
2859 	ret = (ZBX_DB_OK <= rc ? SUCCEED : FAIL);
2860 
2861 #else
2862 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
2863 
2864 	for (i = 0; i < self->rows.values_num; i++)
2865 	{
2866 		zbx_db_value_t	*values = (zbx_db_value_t *)self->rows.values[i];
2867 
2868 #	ifdef HAVE_MULTIROW_INSERT
2869 		if (16 > sql_offset)
2870 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, sql_command);
2871 #	else
2872 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, sql_command);
2873 #	endif
2874 		for (j = 0; j < self->fields.values_num; j++)
2875 		{
2876 			const zbx_db_value_t	*value = &values[j];
2877 
2878 			field = (const ZBX_FIELD *)self->fields.values[j];
2879 
2880 			zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, delim[0 == j]);
2881 
2882 			switch (field->type)
2883 			{
2884 				case ZBX_TYPE_CHAR:
2885 				case ZBX_TYPE_TEXT:
2886 				case ZBX_TYPE_SHORTTEXT:
2887 				case ZBX_TYPE_LONGTEXT:
2888 					zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, '\'');
2889 					zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, value->str);
2890 					zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, '\'');
2891 					break;
2892 				case ZBX_TYPE_INT:
2893 					zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%d", value->i32);
2894 					break;
2895 				case ZBX_TYPE_FLOAT:
2896 					zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, ZBX_FS_DBL,
2897 							value->dbl);
2898 					break;
2899 				case ZBX_TYPE_UINT:
2900 					zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, ZBX_FS_UI64,
2901 							value->ui64);
2902 					break;
2903 				case ZBX_TYPE_ID:
2904 					zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
2905 							DBsql_id_ins(value->ui64));
2906 					break;
2907 				default:
2908 					THIS_SHOULD_NEVER_HAPPEN;
2909 					exit(EXIT_FAILURE);
2910 			}
2911 		}
2912 #	ifdef HAVE_MYSQL
2913 		if (NULL != sql_values)
2914 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, sql_values);
2915 #	endif
2916 
2917 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ")" ZBX_ROW_DL);
2918 
2919 		if (SUCCEED != (ret = DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset)))
2920 			goto out;
2921 	}
2922 
2923 	if (16 < sql_offset)
2924 	{
2925 #	ifdef HAVE_MULTIROW_INSERT
2926 		if (',' == sql[sql_offset - 1])
2927 		{
2928 			sql_offset--;
2929 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2930 		}
2931 #	endif
2932 		DBend_multiple_update(sql, sql_alloc, sql_offset);
2933 
2934 		if (ZBX_DB_OK > DBexecute("%s", sql))
2935 			ret = FAIL;
2936 	}
2937 #endif
2938 
2939 out:
2940 	zbx_free(sql_command);
2941 
2942 #ifndef HAVE_ORACLE
2943 	zbx_free(sql);
2944 
2945 #	ifdef HAVE_MYSQL
2946 	zbx_free(sql_values);
2947 #	endif
2948 #else
2949 	zbx_free(contexts);
2950 #endif
2951 	return ret;
2952 }
2953 
2954 /******************************************************************************
2955  *                                                                            *
2956  * Function: zbx_db_insert_autoincrement                                      *
2957  *                                                                            *
2958  * Purpose: executes the prepared database bulk insert operation              *
2959  *                                                                            *
2960  * Parameters: self - [IN] the bulk insert data                               *
2961  *                                                                            *
2962  ******************************************************************************/
zbx_db_insert_autoincrement(zbx_db_insert_t * self,const char * field_name)2963 void	zbx_db_insert_autoincrement(zbx_db_insert_t *self, const char *field_name)
2964 {
2965 	int	i;
2966 
2967 	for (i = 0; i < self->fields.values_num; i++)
2968 	{
2969 		ZBX_FIELD	*field = (ZBX_FIELD *)self->fields.values[i];
2970 
2971 		if (ZBX_TYPE_ID == field->type && 0 == strcmp(field_name, field->name))
2972 		{
2973 			self->autoincrement = i;
2974 			return;
2975 		}
2976 	}
2977 
2978 	THIS_SHOULD_NEVER_HAPPEN;
2979 	exit(EXIT_FAILURE);
2980 }
2981 
2982 /******************************************************************************
2983  *                                                                            *
2984  * Function: zbx_db_get_database_type                                         *
2985  *                                                                            *
2986  * Purpose: determine is it a server or a proxy database                      *
2987  *                                                                            *
2988  * Return value: ZBX_DB_SERVER - server database                              *
2989  *               ZBX_DB_PROXY - proxy database                                *
2990  *               ZBX_DB_UNKNOWN - an error occurred                           *
2991  *                                                                            *
2992  ******************************************************************************/
zbx_db_get_database_type(void)2993 int	zbx_db_get_database_type(void)
2994 {
2995 	const char	*__function_name = "zbx_db_get_database_type";
2996 
2997 	const char	*result_string;
2998 	DB_RESULT	result;
2999 	DB_ROW		row;
3000 	int		ret = ZBX_DB_UNKNOWN;
3001 
3002 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
3003 
3004 	DBconnect(ZBX_DB_CONNECT_NORMAL);
3005 
3006 	if (NULL == (result = DBselectN("select userid from users", 1)))
3007 	{
3008 		zabbix_log(LOG_LEVEL_DEBUG, "cannot select records from \"users\" table");
3009 		goto out;
3010 	}
3011 
3012 	if (NULL != (row = DBfetch(result)))
3013 	{
3014 		zabbix_log(LOG_LEVEL_DEBUG, "there is at least 1 record in \"users\" table");
3015 		ret = ZBX_DB_SERVER;
3016 	}
3017 	else
3018 	{
3019 		zabbix_log(LOG_LEVEL_DEBUG, "no records in \"users\" table");
3020 		ret = ZBX_DB_PROXY;
3021 	}
3022 
3023 	DBfree_result(result);
3024 out:
3025 	DBclose();
3026 
3027 	switch (ret)
3028 	{
3029 		case ZBX_DB_SERVER:
3030 			result_string = "ZBX_DB_SERVER";
3031 			break;
3032 		case ZBX_DB_PROXY:
3033 			result_string = "ZBX_DB_PROXY";
3034 			break;
3035 		case ZBX_DB_UNKNOWN:
3036 			result_string = "ZBX_DB_UNKNOWN";
3037 			break;
3038 	}
3039 
3040 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, result_string);
3041 
3042 	return ret;
3043 }
3044 
3045 /******************************************************************************
3046  *                                                                            *
3047  * Function: DBlock_record                                                    *
3048  *                                                                            *
3049  * Purpose: locks a record in a table by its primary key and an optional      *
3050  *          constraint field                                                  *
3051  *                                                                            *
3052  * Parameters: table     - [IN] the target table                              *
3053  *             id        - [IN] primary key value                             *
3054  *             add_field - [IN] additional constraint field name (optional)   *
3055  *             add_id    - [IN] constraint field value                        *
3056  *                                                                            *
3057  * Return value: SUCCEED - the record was successfully locked                 *
3058  *               FAIL    - the table does not contain the specified record    *
3059  *                                                                            *
3060  ******************************************************************************/
DBlock_record(const char * table,zbx_uint64_t id,const char * add_field,zbx_uint64_t add_id)3061 int	DBlock_record(const char *table, zbx_uint64_t id, const char *add_field, zbx_uint64_t add_id)
3062 {
3063 	const char	*__function_name = "DBlock_record";
3064 
3065 	DB_RESULT	result;
3066 	const ZBX_TABLE	*t;
3067 	int		ret;
3068 
3069 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
3070 
3071 	if (0 == zbx_db_txn_level())
3072 		zabbix_log(LOG_LEVEL_DEBUG, "%s() called outside of transaction", __function_name);
3073 
3074 	t = DBget_table(table);
3075 
3076 	if (NULL == add_field)
3077 	{
3078 		result = DBselect("select null from %s where %s=" ZBX_FS_UI64 ZBX_FOR_UPDATE, table, t->recid, id);
3079 	}
3080 	else
3081 	{
3082 		result = DBselect("select null from %s where %s=" ZBX_FS_UI64 " and %s=" ZBX_FS_UI64 ZBX_FOR_UPDATE,
3083 				table, t->recid, id, add_field, add_id);
3084 	}
3085 
3086 	if (NULL == DBfetch(result))
3087 		ret = FAIL;
3088 	else
3089 		ret = SUCCEED;
3090 
3091 	DBfree_result(result);
3092 
3093 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
3094 
3095 	return ret;
3096 }
3097 
3098 /******************************************************************************
3099  *                                                                            *
3100  * Function: DBlock_records                                                   *
3101  *                                                                            *
3102  * Purpose: locks a records in a table by its primary key                     *
3103  *                                                                            *
3104  * Parameters: table     - [IN] the target table                              *
3105  *             ids       - [IN] primary key values                            *
3106  *                                                                            *
3107  * Return value: SUCCEED - one or more of the specified records were          *
3108  *                         successfully locked                                *
3109  *               FAIL    - the table does not contain any of the specified    *
3110  *                         records                                            *
3111  *                                                                            *
3112  ******************************************************************************/
DBlock_records(const char * table,const zbx_vector_uint64_t * ids)3113 int	DBlock_records(const char *table, const zbx_vector_uint64_t *ids)
3114 {
3115 	const char	*__function_name = "DBlock_records";
3116 
3117 	DB_RESULT	result;
3118 	const ZBX_TABLE	*t;
3119 	int		ret;
3120 	char		*sql = NULL;
3121 	size_t		sql_alloc = 0, sql_offset = 0;
3122 
3123 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
3124 
3125 	if (0 == zbx_db_txn_level())
3126 		zabbix_log(LOG_LEVEL_DEBUG, "%s() called outside of transaction", __function_name);
3127 
3128 	t = DBget_table(table);
3129 
3130 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "select null from %s where", table);
3131 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, t->recid, ids->values, ids->values_num);
3132 
3133 	result = DBselect("%s" ZBX_FOR_UPDATE, sql);
3134 
3135 	zbx_free(sql);
3136 
3137 	if (NULL == DBfetch(result))
3138 		ret = FAIL;
3139 	else
3140 		ret = SUCCEED;
3141 
3142 	DBfree_result(result);
3143 
3144 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
3145 
3146 	return ret;
3147 }
3148 
3149 /******************************************************************************
3150  *                                                                            *
3151  * Function: zbx_sql_add_host_availability                                    *
3152  *                                                                            *
3153  * Purpose: adds host availability update to sql statement                    *
3154  *                                                                            *
3155  * Parameters: sql        - [IN/OUT] the sql statement                        *
3156  *             sql_alloc  - [IN/OUT] the number of bytes allocated for sql    *
3157  *                                   statement                                *
3158  *             sql_offset - [IN/OUT] the number of bytes used in sql          *
3159  *                                   statement                                *
3160  *             ha           [IN] the host availability data                   *
3161  *                                                                            *
3162  ******************************************************************************/
zbx_sql_add_host_availability(char ** sql,size_t * sql_alloc,size_t * sql_offset,const zbx_host_availability_t * ha)3163 int	zbx_sql_add_host_availability(char **sql, size_t *sql_alloc, size_t *sql_offset,
3164 		const zbx_host_availability_t *ha)
3165 {
3166 	const char	*field_prefix[ZBX_AGENT_MAX] = {"", "snmp_", "ipmi_", "jmx_"};
3167 	char		delim = ' ';
3168 	int		i;
3169 
3170 	if (FAIL == zbx_host_availability_is_set(ha))
3171 		return FAIL;
3172 
3173 	zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "update hosts set");
3174 
3175 	for (i = 0; i < ZBX_AGENT_MAX; i++)
3176 	{
3177 		if (0 != (ha->agents[i].flags & ZBX_FLAGS_AGENT_STATUS_AVAILABLE))
3178 		{
3179 			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%c%savailable=%d", delim, field_prefix[i],
3180 					(int)ha->agents[i].available);
3181 			delim = ',';
3182 		}
3183 
3184 		if (0 != (ha->agents[i].flags & ZBX_FLAGS_AGENT_STATUS_ERROR))
3185 		{
3186 			char	*error_esc;
3187 
3188 			error_esc = DBdyn_escape_field("hosts", "error", ha->agents[i].error);
3189 			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%c%serror='%s'", delim, field_prefix[i],
3190 					error_esc);
3191 			zbx_free(error_esc);
3192 			delim = ',';
3193 		}
3194 
3195 		if (0 != (ha->agents[i].flags & ZBX_FLAGS_AGENT_STATUS_ERRORS_FROM))
3196 		{
3197 			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%c%serrors_from=%d", delim, field_prefix[i],
3198 					ha->agents[i].errors_from);
3199 			delim = ',';
3200 		}
3201 
3202 		if (0 != (ha->agents[i].flags & ZBX_FLAGS_AGENT_STATUS_DISABLE_UNTIL))
3203 		{
3204 			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%c%sdisable_until=%d", delim, field_prefix[i],
3205 					ha->agents[i].disable_until);
3206 			delim = ',';
3207 		}
3208 	}
3209 
3210 	zbx_snprintf_alloc(sql, sql_alloc, sql_offset, " where hostid=" ZBX_FS_UI64, ha->hostid);
3211 
3212 	return SUCCEED;
3213 }
3214 
3215 /******************************************************************************
3216  *                                                                            *
3217  * Function: DBget_user_by_active_session                                     *
3218  *                                                                            *
3219  * Purpose: validate that session is active and get associated user data      *
3220  *                                                                            *
3221  * Parameters: sessionid - [IN] the session id to validate                    *
3222  *             user      - [OUT] user information                             *
3223  *                                                                            *
3224  * Return value:  SUCCEED - session is active and user data was retrieved     *
3225  *                FAIL    - otherwise                                         *
3226  *                                                                            *
3227  ******************************************************************************/
DBget_user_by_active_session(const char * sessionid,zbx_user_t * user)3228 int	DBget_user_by_active_session(const char *sessionid, zbx_user_t *user)
3229 {
3230 	const char	*__function_name = "DBget_user_by_active_session";
3231 	char		*sessionid_esc;
3232 	int		ret = FAIL;
3233 	DB_RESULT	result;
3234 	DB_ROW		row;
3235 
3236 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() sessionid:%s", __function_name, sessionid);
3237 
3238 	sessionid_esc = DBdyn_escape_string(sessionid);
3239 
3240 	if (NULL == (result = DBselect(
3241 			"select u.userid,u.type"
3242 				" from sessions s,users u"
3243 			" where s.userid=u.userid"
3244 				" and s.sessionid='%s'"
3245 				" and s.status=%d",
3246 			sessionid_esc, ZBX_SESSION_ACTIVE)))
3247 	{
3248 		goto out;
3249 	}
3250 
3251 	if (NULL == (row = DBfetch(result)))
3252 		goto out;
3253 
3254 	ZBX_STR2UINT64(user->userid, row[0]);
3255 	user->type = atoi(row[1]);
3256 
3257 	ret = SUCCEED;
3258 out:
3259 	DBfree_result(result);
3260 	zbx_free(sessionid_esc);
3261 
3262 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
3263 
3264 	return ret;
3265 }
3266