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