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