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