1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2003-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2016 Planets Communications B.V.
6 Copyright (C) 2013-2013 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23 /*
24 * João Henrique Freitas, December 2007
25 * based upon work done by Dan Langille, December 2003 and
26 * by Kern Sibbald, March 2000
27 * Major rewrite by Marco van Wieringen, January 2010 for catalog refactoring.
28 */
29 /**
30 * @file
31 * BAREOS Catalog Database routines specific to DBI
32 * These are DBI specific routines
33 */
34 /*
35 * This code only compiles against a recent version of libdbi. The current
36 * release found on the libdbi website (0.8.3) won't work for this code.
37 *
38 * You find the libdbi library on http://sourceforge.net/projects/libdbi
39 *
40 * A fairly recent version of libdbi from CVS works, so either make sure
41 * your distribution has a fairly recent version of libdbi installed or
42 * clone the CVS repositories from sourceforge and compile that code and
43 * install it.
44 *
45 * You need:
46 * cvs co :pserver:anonymous@libdbi.cvs.sourceforge.net:/cvsroot/libdbi
47 * cvs co :pserver:anonymous@libdbi-drivers.cvs.sourceforge.net:/cvsroot/libdbi-drivers
48 */
49
50 #include "include/bareos.h"
51
52 #ifdef HAVE_DBI
53
54 #include "cats.h"
55 #include <dbi/dbi.h>
56 #include <dbi/dbi-dev.h>
57 #include <bdb_dbi.h>
58
59 /* -----------------------------------------------------------------------
60 *
61 * DBI dependent defines and subroutines
62 *
63 * -----------------------------------------------------------------------
64 */
65
66 /**
67 * List of open databases
68 */
69 static dlist *db_list = NULL;
70
71 /**
72 * Control allocated fields by dbi_getvalue
73 */
74 static dlist *dbi_getvalue_list = NULL;
75
76 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
77
78 typedef int (*custom_function_insert_t)(void*, const char*, int);
79 typedef char* (*custom_function_error_t)(void*);
80 typedef int (*custom_function_end_t)(void*, const char*);
81
BareosDbDBI(JobControlRecord * jcr,const char * db_driver,const char * db_name,const char * db_user,const char * db_password,const char * db_address,int db_port,const char * db_socket,bool mult_db_connections,bool disable_batch_insert,bool need_private,bool try_reconnect,bool exit_on_fatal)82 BareosDbDBI::BareosDbDBI(JobControlRecord *jcr,
83 const char *db_driver,
84 const char *db_name,
85 const char *db_user,
86 const char *db_password,
87 const char *db_address,
88 int db_port,
89 const char *db_socket,
90 bool mult_db_connections,
91 bool disable_batch_insert,
92 bool need_private,
93 bool try_reconnect,
94 bool exit_on_fatal)
95 {
96 char *p;
97 char new_db_driver[10];
98 char db_driverdir[256];
99 DbiFieldGet *field;
100
101 p = (char *)(db_driver + 4);
102 if (Bstrcasecmp(p, "mysql")) {
103 db_type_ = SQL_TYPE_MYSQL;
104 bstrncpy(new_db_driver, "mysql", sizeof(new_db_driver));
105 } else if (Bstrcasecmp(p, "postgresql")) {
106 db_type_ = SQL_TYPE_POSTGRESQL;
107 bstrncpy(new_db_driver, "pgsql", sizeof(new_db_driver));
108 } else if (Bstrcasecmp(p, "sqlite3")) {
109 db_type_ = SQL_TYPE_SQLITE3;
110 bstrncpy(new_db_driver, "sqlite3", sizeof(new_db_driver));
111 } else {
112 Jmsg(jcr, M_ABORT, 0, _("Unknown database type: %s\n"), p);
113 return;
114 }
115
116 /*
117 * Set db_driverdir whereis is the libdbi drivers
118 */
119 bstrncpy(db_driverdir, DBI_DRIVER_DIR, 255);
120
121 /*
122 * Initialize the parent class members.
123 */
124 db_interface_type_ = SQL_INTERFACE_TYPE_DBI;
125 db_name_ = bstrdup(db_name);
126 db_user_ = bstrdup(db_user);
127 if (db_password) {
128 db_password_ = bstrdup(db_password);
129 }
130 if (db_address) {
131 db_address_ = bstrdup(db_address);
132 }
133 if (db_socket) {
134 db_socket_ = bstrdup(db_socket);
135 }
136 if (db_driverdir) {
137 db_driverdir_ = bstrdup(db_driverdir);
138 }
139 db_driver_ = bstrdup(new_db_driver);
140 db_port_ = db_port;
141 if (disable_batch_insert) {
142 disabled_batch_insert_ = true;
143 have_batch_insert_ = false;
144 } else {
145 disabled_batch_insert_ = false;
146 #if defined(USE_BATCH_FILE_INSERT)
147 #ifdef HAVE_DBI_BATCH_FILE_INSERT
148 have_batch_insert_ = true;
149 #else
150 have_batch_insert_ = false;
151 #endif /* HAVE_DBI_BATCH_FILE_INSERT */
152 #else
153 have_batch_insert_ = false;
154 #endif /* USE_BATCH_FILE_INSERT */
155 }
156 errmsg = GetPoolMemory(PM_EMSG); /* get error message buffer */
157 *errmsg = 0;
158 cmd = GetPoolMemory(PM_EMSG); /* get command buffer */
159 cached_path = GetPoolMemory(PM_FNAME);
160 cached_path_id = 0;
161 ref_count_ = 1;
162 fname = GetPoolMemory(PM_FNAME);
163 path = GetPoolMemory(PM_FNAME);
164 esc_name = GetPoolMemory(PM_FNAME);
165 esc_path = GetPoolMemory(PM_FNAME);
166 esc_obj = GetPoolMemory(PM_FNAME);
167 allow_transactions_ = mult_db_connections;
168 is_private_ = need_private;
169 try_reconnect_ = try_reconnect;
170 exit_on_fatal_ = exit_on_fatal;
171
172 /*
173 * Initialize the private members.
174 */
175 db_handle_ = NULL;
176 result_ = NULL;
177 field_get_ = NULL;
178
179 /*
180 * Put the db in the list.
181 */
182 if (db_list == NULL) {
183 db_list = New(dlist(this, &this->link_));
184 dbi_getvalue_list = New(dlist(field, &field->link));
185 }
186 db_list->append(this);
187 }
188
~BareosDbDBI()189 BareosDbDBI::~BareosDbDBI()
190 {
191 }
192
193 /**
194 * Now actually open the database. This can generate errors,
195 * which are returned in the errmsg
196 *
197 * DO NOT close the database or delete mdb here !!!!
198 */
OpenDatabase(JobControlRecord * jcr)199 bool BareosDbDBI::OpenDatabase(JobControlRecord *jcr)
200 {
201 bool retval = false;
202 int errstat;
203 int dbstat;
204 uint8_t len;
205 const char *dbi_errmsg;
206 char buf[10], *port;
207 int numdrivers;
208 char *new_db_name = NULL;
209 char *new_db_dir = NULL;
210
211 P(mutex);
212 if (connected_) {
213 retval = true;
214 goto bail_out;
215 }
216
217 if ((errstat=RwlInit(&lock_)) != 0) {
218 BErrNo be;
219 Mmsg1(&errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
220 be.bstrerror(errstat));
221 goto bail_out;
222 }
223
224 if (db_port_) {
225 Bsnprintf(buf, sizeof(buf), "%d", db_port_);
226 port = buf;
227 } else {
228 port = NULL;
229 }
230
231 numdrivers = dbi_initialize_r(db_driverdir_, &(instance_));
232 if (numdrivers < 0) {
233 Mmsg2(&errmsg, _("Unable to locate the DBD drivers to DBI interface in: \n"
234 "db_driverdir=%s. It is probaly not found any drivers\n"),
235 db_driverdir_,numdrivers);
236 goto bail_out;
237 }
238 db_handle_ = (void **)dbi_conn_new_r(db_driver_, instance_);
239 /*
240 * Can be many types of databases
241 */
242 switch (db_type_) {
243 case SQL_TYPE_MYSQL:
244 dbi_conn_set_option(db_handle_, "host", db_address_); /* default = localhost */
245 dbi_conn_set_option(db_handle_, "port", port); /* default port */
246 dbi_conn_set_option(db_handle_, "username", db_user_); /* login name */
247 dbi_conn_set_option(db_handle_, "password", db_password_); /* password */
248 dbi_conn_set_option(db_handle_, "dbname", db_name_); /* database name */
249 break;
250 case SQL_TYPE_POSTGRESQL:
251 dbi_conn_set_option(db_handle_, "host", db_address_);
252 dbi_conn_set_option(db_handle_, "port", port);
253 dbi_conn_set_option(db_handle_, "username", db_user_);
254 dbi_conn_set_option(db_handle_, "password", db_password_);
255 dbi_conn_set_option(db_handle_, "dbname", db_name_);
256 break;
257 case SQL_TYPE_SQLITE3:
258 len = strlen(working_directory) + 5;
259 new_db_dir = (char *)malloc(len);
260 strcpy(new_db_dir, working_directory);
261 strcat(new_db_dir, "/");
262 len = strlen(db_name_) + 5;
263 new_db_name = (char *)malloc(len);
264 strcpy(new_db_name, db_name_);
265 strcat(new_db_name, ".db");
266 dbi_conn_set_option(db_handle_, "sqlite3_dbdir", new_db_dir);
267 dbi_conn_set_option(db_handle_, "dbname", new_db_name);
268 Dmsg2(500, "SQLITE: %s %s\n", new_db_dir, new_db_name);
269 free(new_db_dir);
270 free(new_db_name);
271 break;
272 }
273
274 /*
275 * If connection fails, try at 5 sec intervals for 30 seconds.
276 */
277 for (int retry=0; retry < 6; retry++) {
278 dbstat = dbi_conn_connect(db_handle_);
279 if (dbstat == 0) {
280 break;
281 }
282
283 dbi_conn_error(db_handle_, &dbi_errmsg);
284 Dmsg1(50, "dbi error: %s\n", dbi_errmsg);
285
286 Bmicrosleep(5, 0);
287 }
288
289 if (dbstat != 0 ) {
290 Mmsg3(&errmsg, _("Unable to connect to DBI interface. Type=%s Database=%s User=%s\n"
291 "Possible causes: SQL server not running; password incorrect; max_connections exceeded.\n"),
292 db_driver_, db_name_, db_user_);
293 goto bail_out;
294 }
295
296 Dmsg0(50, "dbi_real_connect done\n");
297 Dmsg3(50, "db_user=%s db_name=%s db_password=%s\n",
298 db_user_, db_name_,
299 (db_password_ == NULL) ? "(NULL)" : db_password_);
300
301 connected_ = true;
302
303 if (!CheckTablesVersion(jcr, this)) {
304 goto bail_out;
305 }
306
307 switch (db_type_) {
308 case SQL_TYPE_MYSQL:
309 /*
310 * Set connection timeout to 8 days specialy for batch mode
311 */
312 SqlQueryWithoutHandler("SET wait_timeout=691200");
313 SqlQueryWithoutHandler("SET interactive_timeout=691200");
314 break;
315 case SQL_TYPE_POSTGRESQL:
316 /*
317 * Tell PostgreSQL we are using standard conforming strings
318 * and avoid warnings such as:
319 * WARNING: nonstandard use of \\ in a string literal
320 */
321 SqlQueryWithoutHandler("SET datestyle TO 'ISO, YMD'");
322 SqlQueryWithoutHandler("SET standard_conforming_strings=on");
323 break;
324 }
325
326 retval = true;
327
328 bail_out:
329 V(mutex);
330 return retval;
331 }
332
CloseDatabase(JobControlRecord * jcr)333 void BareosDbDBI::CloseDatabase(JobControlRecord *jcr)
334 {
335 if (connected_) {
336 EndTransaction(jcr);
337 }
338 P(mutex);
339 ref_count_--;
340 if (ref_count_ == 0) {
341 if (connected_) {
342 SqlFreeResult();
343 }
344 db_list->remove(this);
345 if (connected_ && db_handle_) {
346 dbi_shutdown_r(instance_);
347 db_handle_ = NULL;
348 instance_ = NULL;
349 }
350 if (RwlIsInit(&lock_)) {
351 RwlDestroy(&lock_);
352 }
353 FreePoolMemory(errmsg);
354 FreePoolMemory(cmd);
355 FreePoolMemory(cached_path);
356 FreePoolMemory(fname);
357 FreePoolMemory(path);
358 FreePoolMemory(esc_name);
359 FreePoolMemory(esc_path);
360 FreePoolMemory(esc_obj);
361 if (db_driver_) {
362 free(db_driver_);
363 }
364 if (db_name_) {
365 free(db_name_);
366 }
367 if (db_user_) {
368 free(db_user_);
369 }
370 if (db_password_) {
371 free(db_password_);
372 }
373 if (db_address_) {
374 free(db_address_);
375 }
376 if (db_socket_) {
377 free(db_socket_);
378 }
379 if (db_driverdir_) {
380 free(db_driverdir_);
381 }
382 delete this;
383 if (db_list->size() == 0) {
384 delete db_list;
385 db_list = NULL;
386 }
387 }
388 V(mutex);
389 }
390
ValidateConnection(void)391 bool BareosDbDBI::ValidateConnection(void)
392 {
393 bool retval;
394
395 DbLock(this);
396 if (dbi_conn_ping(db_handle_) == 1) {
397 retval = true;
398 goto bail_out;
399 } else {
400 retval = false;
401 goto bail_out;
402 }
403
404 bail_out:
405 DbUnlock(this);
406 return retval;
407 }
408
409 /**
410 * Escape strings so that DBI is happy
411 *
412 * NOTE! len is the length of the old string. Your new
413 * string must be long enough (max 2*old+1) to hold
414 * the escaped output.
415 *
416 * dbi_conn_quote_string_copy receives a pointer to pointer.
417 * We need copy the value of pointer to snew because libdbi change the
418 * pointer
419 */
EscapeString(JobControlRecord * jcr,char * snew,char * old,int len)420 void BareosDbDBI::EscapeString(JobControlRecord *jcr, char *snew, char *old, int len)
421 {
422 char *inew;
423 char *pnew;
424
425 if (len == 0) {
426 snew[0] = 0;
427 } else {
428 /*
429 * Correct the size of old basead in len and copy new string to inew
430 */
431 inew = (char *)malloc(sizeof(char) * len + 1);
432 bstrncpy(inew,old,len + 1);
433 /*
434 * Escape the correct size of old
435 */
436 dbi_conn_escape_string_copy(db_handle_, inew, &pnew);
437 free(inew);
438 /*
439 * Copy the escaped string to snew
440 */
441 bstrncpy(snew, pnew, 2 * len + 1);
442 }
443
444 Dmsg2(500, "dbi_conn_escape_string_copy %p %s\n",snew,snew);
445 }
446
447 /**
448 * Escape binary object so that DBI is happy
449 * Memory is stored in BareosDb struct, no need to free it
450 */
EscapeObject(JobControlRecord * jcr,char * old,int len)451 char *BareosDbDBI::EscapeObject(JobControlRecord *jcr, char *old, int len)
452 {
453 size_t new_len;
454 char *pnew;
455
456 if (len == 0) {
457 esc_obj[0] = 0;
458 } else {
459 new_len = dbi_conn_escape_string_copy(db_handle_, esc_obj, &pnew);
460 esc_obj = CheckPoolMemorySize(esc_obj, new_len+1);
461 memcpy(esc_obj, pnew, new_len);
462 }
463
464 return esc_obj;
465 }
466
467 /**
468 * Unescape binary object so that DBI is happy
469 */
UnescapeObject(JobControlRecord * jcr,char * from,int32_t expected_len,POOLMEM * & dest,int32_t * dest_len)470 void BareosDbDBI::UnescapeObject(JobControlRecord *jcr, char *from, int32_t expected_len,
471 POOLMEM *&dest, int32_t *dest_len)
472 {
473 if (!from) {
474 dest[0] = '\0';
475 *dest_len = 0;
476 return;
477 }
478 dest = CheckPoolMemorySize(dest, expected_len + 1);
479 *dest_len = expected_len;
480 memcpy(dest, from, expected_len);
481 dest[expected_len] = '\0';
482 }
483
484 /**
485 * Start a transaction. This groups inserts and makes things
486 * much more efficient. Usually started when inserting
487 * file attributes.
488 */
StartTransaction(JobControlRecord * jcr)489 void BareosDbDBI::StartTransaction(JobControlRecord *jcr)
490 {
491 if (!jcr->attr) {
492 jcr->attr = GetPoolMemory(PM_FNAME);
493 }
494 if (!jcr->ar) {
495 jcr->ar = (AttributesDbRecord *)malloc(sizeof(AttributesDbRecord));
496 }
497
498 switch (db_type_) {
499 case SQL_TYPE_SQLITE3:
500 if (!allow_transactions_) {
501 return;
502 }
503
504 DbLock(this);
505 /*
506 * Allow only 10,000 changes per transaction
507 */
508 if (transaction_ && changes > 10000) {
509 EndTransaction(jcr);
510 }
511 if (!transaction_) {
512 SqlQueryWithoutHandler("BEGIN"); /* begin transaction */
513 Dmsg0(400, "Start SQLite transaction\n");
514 transaction_ = true;
515 }
516 DbUnlock(this);
517 break;
518 case SQL_TYPE_POSTGRESQL:
519 /*
520 * This is turned off because transactions break
521 * if multiple simultaneous jobs are run.
522 */
523 if (!allow_transactions_) {
524 return;
525 }
526
527 DbLock(this);
528 /*
529 * Allow only 25,000 changes per transaction
530 */
531 if (transaction_ && changes > 25000) {
532 EndTransaction(jcr);
533 }
534 if (!transaction_) {
535 SqlQueryWithoutHandler("BEGIN"); /* begin transaction */
536 Dmsg0(400, "Start PosgreSQL transaction\n");
537 transaction_ = true;
538 }
539 DbUnlock(this);
540 break;
541 case SQL_TYPE_INGRES:
542 if (!allow_transactions_) {
543 return;
544 }
545
546 DbLock(this);
547 /*
548 * Allow only 25,000 changes per transaction
549 */
550 if (transaction_ && changes > 25000) {
551 EndTransaction(jcr);
552 }
553 if (!transaction_) {
554 SqlQueryWithoutHandler("BEGIN"); /* begin transaction */
555 Dmsg0(400, "Start Ingres transaction\n");
556 transaction_ = true;
557 }
558 DbUnlock(this);
559 break;
560 default:
561 break;
562 }
563 }
564
EndTransaction(JobControlRecord * jcr)565 void BareosDbDBI::EndTransaction(JobControlRecord *jcr)
566 {
567 if (jcr && jcr->cached_attribute) {
568 Dmsg0(400, "Flush last cached attribute.\n");
569 if (!CreateAttributesRecord(jcr, jcr->ar)) {
570 Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), strerror());
571 }
572 jcr->cached_attribute = false;
573 }
574
575 switch (db_type_) {
576 case SQL_TYPE_SQLITE3:
577 if (!allow_transactions_) {
578 return;
579 }
580
581 DbLock(this);
582 if (transaction_) {
583 SqlQueryWithoutHandler("COMMIT"); /* end transaction */
584 transaction_ = false;
585 Dmsg1(400, "End SQLite transaction changes=%d\n", changes);
586 }
587 changes = 0;
588 DbUnlock(this);
589 break;
590 case SQL_TYPE_POSTGRESQL:
591 if (!allow_transactions_) {
592 return;
593 }
594
595 DbLock(this);
596 if (transaction_) {
597 SqlQueryWithoutHandler("COMMIT"); /* end transaction */
598 transaction_ = false;
599 Dmsg1(400, "End PostgreSQL transaction changes=%d\n", changes);
600 }
601 changes = 0;
602 DbUnlock(this);
603 break;
604 case SQL_TYPE_INGRES:
605 if (!allow_transactions_) {
606 return;
607 }
608
609 DbLock(this);
610 if (transaction_) {
611 SqlQueryWithoutHandler("COMMIT"); /* end transaction */
612 transaction_ = false;
613 Dmsg1(400, "End Ingres transaction changes=%d\n", changes);
614 }
615 changes = 0;
616 DbUnlock(this);
617 break;
618 default:
619 break;
620 }
621 }
622
623 /**
624 * Submit a general SQL command (cmd), and for each row returned,
625 * the ResultHandler is called with the ctx.
626 */
SqlQueryWithHandler(const char * query,DB_RESULT_HANDLER * ResultHandler,void * ctx)627 bool BareosDbDBI::SqlQueryWithHandler(const char *query, DB_RESULT_HANDLER *ResultHandler, void *ctx)
628 {
629 bool retval = true;
630 SQL_ROW row;
631
632 Dmsg1(500, "SqlQueryWithHandler starts with %s\n", query);
633
634 DbLock(this);
635 if (!SqlQueryWithoutHandler(query, QF_STORE_RESULT)) {
636 Mmsg(errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror());
637 Dmsg0(500, "SqlQueryWithHandler failed\n");
638 retval = false;
639 goto bail_out;
640 }
641
642 Dmsg0(500, "SqlQueryWithHandler succeeded. checking handler\n");
643
644 if (ResultHandler != NULL) {
645 Dmsg0(500, "SqlQueryWithHandler invoking handler\n");
646 while ((row = SqlFetchRow()) != NULL) {
647 Dmsg0(500, "SqlQueryWithHandler SqlFetchRow worked\n");
648 if (ResultHandler(ctx, num_fields_, row))
649 break;
650 }
651 SqlFreeResult();
652 }
653
654 Dmsg0(500, "SqlQueryWithHandler finished\n");
655
656 bail_out:
657 DbUnlock(this);
658 return retval;
659 }
660
661 /**
662 * Note, if this routine returns 1 (failure), BAREOS expects
663 * that no result has been stored.
664 *
665 * Returns: true on success
666 * false on failure
667 */
SqlQueryWithoutHandler(const char * query,int flags)668 bool BareosDbDBI::SqlQueryWithoutHandler(const char *query, int flags)
669 {
670 bool retval = false;
671 const char *dbi_errmsg;
672
673 Dmsg1(500, "SqlQueryWithoutHandler starts with %s\n", query);
674
675 /*
676 * We are starting a new query. reset everything.
677 */
678 num_rows_ = -1;
679 row_number_ = -1;
680 field_number_ = -1;
681
682 if (result_) {
683 dbi_result_free(result_); /* hmm, someone forgot to free?? */
684 result_ = NULL;
685 }
686
687 result_ = (void **)dbi_conn_query(db_handle_, query);
688
689 if (!result_) {
690 Dmsg2(50, "Query failed: %s %p\n", query, result_);
691 goto bail_out;
692 }
693
694 status_ = (dbi_error_flag) dbi_conn_error(db_handle_, &dbi_errmsg);
695 if (status_ == DBI_ERROR_NONE) {
696 Dmsg1(500, "we have a result\n", query);
697
698 /*
699 * How many fields in the set?
700 * num_fields starting at 1
701 */
702 num_fields_ = dbi_result_get_numfields(result_);
703 Dmsg1(500, "we have %d fields\n", num_fields_);
704 /*
705 * If no result num_rows is 0
706 */
707 num_rows_ = dbi_result_get_numrows(result_);
708 Dmsg1(500, "we have %d rows\n", num_rows_);
709
710 status_ = (dbi_error_flag) 0; /* succeed */
711 } else {
712 Dmsg1(50, "Result status failed: %s\n", query);
713 goto bail_out;
714 }
715
716 Dmsg0(500, "SqlQueryWithoutHandler finishing\n");
717 retval = true;
718 goto ok_out;
719
720 bail_out:
721 status_ = (dbi_error_flag) dbi_conn_error(db_handle_, &dbi_errmsg);
722 //dbi_conn_error(db_handle_, &dbi_errmsg);
723 Dmsg4(500, "SqlQueryWithoutHandler we failed dbi error: "
724 "'%s' '%p' '%d' flag '%d''\n", dbi_errmsg, result_, result_, status_);
725 dbi_result_free(result_);
726 result_ = NULL;
727 status_ = (dbi_error_flag) 1; /* failed */
728
729 ok_out:
730 return retval;
731 }
732
SqlFreeResult(void)733 void BareosDbDBI::SqlFreeResult(void)
734 {
735 DbiFieldGet *f;
736
737 DbLock(this);
738 if (result_) {
739 dbi_result_free(result_);
740 result_ = NULL;
741 }
742 if (rows_) {
743 free(rows_);
744 rows_ = NULL;
745 }
746 /*
747 * Now is time to free all value return by dbi_get_value
748 * this is necessary because libdbi don't free memory return by yours results
749 * and BAREOS has some routine wich call more than once time sql_fetch_row
750 *
751 * Using a queue to store all pointer allocate is a good way to free all things
752 * when necessary
753 */
754 foreach_dlist(f, dbi_getvalue_list) {
755 free(f->value);
756 free(f);
757 }
758 if (fields_) {
759 free(fields_);
760 fields_ = NULL;
761 }
762 num_rows_ = num_fields_ = 0;
763 DbUnlock(this);
764 }
765
766 /* dbi_getvalue
767 * like PQgetvalue;
768 * char *PQgetvalue(const PGresult *res,
769 * int row_number,
770 * int column_number);
771 *
772 * use dbi_result_seek_row to search in result set
773 * use example to return only strings
774 */
dbi_getvalue(dbi_result * result,int row_number,unsigned int column_number)775 static char *dbi_getvalue(dbi_result *result, int row_number, unsigned int column_number)
776 {
777 char *buf = NULL;
778 const char *dbi_errmsg;
779 const char *field_name;
780 unsigned short dbitype;
781 size_t field_length;
782 int64_t num;
783
784 /* correct the index for dbi interface
785 * dbi index begins 1
786 * I prefer do not change others functions
787 */
788 Dmsg3(600, "dbi_getvalue pre-starting result '%p' row number '%d' column number '%d'\n",
789 result, row_number, column_number);
790
791 column_number++;
792
793 if(row_number == 0) {
794 row_number++;
795 }
796
797 Dmsg3(600, "dbi_getvalue starting result '%p' row number '%d' column number '%d'\n",
798 result, row_number, column_number);
799
800 if(dbi_result_seek_row(result, row_number)) {
801
802 field_name = dbi_result_get_field_name(result, column_number);
803 field_length = dbi_result_get_field_length(result, field_name);
804 dbitype = dbi_result_get_field_type_idx(result,column_number);
805
806 Dmsg3(500, "dbi_getvalue start: type: '%d' "
807 "field_length bytes: '%d' fieldname: '%s'\n",
808 dbitype, field_length, field_name);
809
810 if(field_length) {
811 //buf = (char *)malloc(sizeof(char *) * field_length + 1);
812 buf = (char *)malloc(field_length + 1);
813 } else {
814 /*
815 * if numbers
816 */
817 buf = (char *)malloc(sizeof(char *) * 50);
818 }
819
820 switch (dbitype) {
821 case DBI_TYPE_INTEGER:
822 num = dbi_result_get_longlong(result, field_name);
823 edit_int64(num, buf);
824 field_length = strlen(buf);
825 break;
826 case DBI_TYPE_STRING:
827 if(field_length) {
828 field_length = Bsnprintf(buf, field_length + 1, "%s",
829 dbi_result_get_string(result, field_name));
830 } else {
831 buf[0] = 0;
832 }
833 break;
834 case DBI_TYPE_BINARY:
835 /*
836 * dbi_result_get_binary return a NULL pointer if value is empty
837 * following, change this to what BAREOS expected
838 */
839 if(field_length) {
840 field_length = Bsnprintf(buf, field_length + 1, "%s",
841 dbi_result_get_binary(result, field_name));
842 } else {
843 buf[0] = 0;
844 }
845 break;
846 case DBI_TYPE_DATETIME:
847 time_t last;
848 struct tm tm;
849
850 last = dbi_result_get_datetime(result, field_name);
851
852 if(last == -1) {
853 field_length = Bsnprintf(buf, 20, "0000-00-00 00:00:00");
854 } else {
855 Blocaltime(&last, &tm);
856 field_length = Bsnprintf(buf, 20, "%04d-%02d-%02d %02d:%02d:%02d",
857 (tm.tm_year + 1900), (tm.tm_mon + 1), tm.tm_mday,
858 tm.tm_hour, tm.tm_min, tm.tm_sec);
859 }
860 break;
861 }
862
863 } else {
864 dbi_conn_error(dbi_result_get_conn(result), &dbi_errmsg);
865 Dmsg1(500, "dbi_getvalue error: %s\n", dbi_errmsg);
866 }
867
868 Dmsg3(500, "dbi_getvalue finish buffer: '%p' num bytes: '%d' data: '%s'\n",
869 buf, field_length, buf);
870
871 /*
872 * Don't worry about this buf
873 */
874 return buf;
875 }
876
SqlFetchRow(void)877 SQL_ROW BareosDbDBI::SqlFetchRow(void)
878 {
879 int j;
880 SQL_ROW row = NULL; /* by default, return NULL */
881
882 Dmsg0(500, "SqlFetchRow start\n");
883 if ((!rows_ || rows_size_ < num_fields_) && num_rows_ > 0) {
884 if (rows_) {
885 Dmsg0(500, "SqlFetchRow freeing space\n");
886 Dmsg2(500, "SqlFetchRow row: '%p' num_fields: '%d'\n", rows_, num_fields_);
887 if (num_rows_ != 0) {
888 for (j = 0; j < num_fields_; j++) {
889 Dmsg2(500, "SqlFetchRow row '%p' '%d'\n", rows_[j], j);
890 if (rows_[j]) {
891 free(rows_[j]);
892 }
893 }
894 }
895 free(rows_);
896 }
897 Dmsg1(500, "we need space for %d bytes\n", sizeof(char *) * num_fields_);
898 rows_ = (SQL_ROW)malloc(sizeof(char *) * num_fields_);
899 rows_size_ = num_fields_;
900
901 /*
902 * Now reset the row_number now that we have the space allocated
903 */
904 row_number_ = 1;
905 }
906
907 /*
908 * If still within the result set
909 */
910 if (row_number_ <= num_rows_ && row_number_ != DBI_ERROR_BADPTR) {
911 Dmsg2(500, "SqlFetchRow row number '%d' is acceptable (1..%d)\n", row_number_, num_rows_);
912 /*
913 * Get each value from this row
914 */
915 for (j = 0; j < num_fields_; j++) {
916 rows_[j] = dbi_getvalue(result_, row_number_, j);
917 /*
918 * Allocate space to queue row
919 */
920 field_get_ = (DbiFieldGet *)malloc(sizeof(DbiFieldGet));
921 /*
922 * Store the pointer in queue
923 */
924 field_get_->value = rows_[j];
925 Dmsg4(500, "SqlFetchRow row[%d] field: '%p' in queue: '%p' has value: '%s'\n",
926 j, rows_[j], field_get_->value, rows_[j]);
927 /*
928 * Insert in queue to future free
929 */
930 dbi_getvalue_list->append(field_get_);
931 }
932 /*
933 * Increment the row number for the next call
934 */
935 row_number_++;
936
937 row = rows_;
938 } else {
939 Dmsg2(500, "SqlFetchRow row number '%d' is NOT acceptable (1..%d)\n", row_number_, num_rows_);
940 }
941
942 Dmsg1(500, "SqlFetchRow finishes returning %p\n", row);
943
944 return row;
945 }
946
sql_strerror(void)947 const char *BareosDbDBI::sql_strerror(void)
948 {
949 const char *dbi_errmsg;
950
951 dbi_conn_error(db_handle_, &dbi_errmsg);
952
953 return dbi_errmsg;
954 }
955
SqlDataSeek(int row)956 void BareosDbDBI::SqlDataSeek(int row)
957 {
958 /*
959 * Set the row number to be returned on the next call to sql_fetch_row
960 */
961 row_number_ = row;
962 }
963
SqlAffectedRows(void)964 int BareosDbDBI::SqlAffectedRows(void)
965 {
966 #if 0
967 return dbi_result_get_numrows_affected(result);
968 #else
969 return 1;
970 #endif
971 }
972
SqlInsertAutokeyRecord(const char * query,const char * table_name)973 uint64_t BareosDbDBI::SqlInsertAutokeyRecord(const char *query, const char *table_name)
974 {
975 char sequence[30];
976 uint64_t id = 0;
977
978 /*
979 * First execute the insert query and then retrieve the currval.
980 */
981 if (!SqlQueryWithoutHandler(query)) {
982 return 0;
983 }
984
985 num_rows_ = SqlAffectedRows();
986 if (num_rows_ != 1) {
987 return 0;
988 }
989
990 changes++;
991
992 /*
993 * Obtain the current value of the sequence that
994 * provides the serial value for primary key of the table.
995 *
996 * currval is local to our session. It is not affected by
997 * other transactions.
998 *
999 * Determine the name of the sequence.
1000 * PostgreSQL automatically creates a sequence using
1001 * <table>_<column>_seq.
1002 * At the time of writing, all tables used this format for
1003 * for their primary key: <table>id
1004 * Except for basefiles which has a primary key on baseid.
1005 * Therefore, we need to special case that one table.
1006 *
1007 * everything else can use the PostgreSQL formula.
1008 */
1009 if (db_type_ == SQL_TYPE_POSTGRESQL) {
1010 if (Bstrcasecmp(table_name, "basefiles")) {
1011 bstrncpy(sequence, "basefiles_baseid", sizeof(sequence));
1012 } else {
1013 bstrncpy(sequence, table_name, sizeof(sequence));
1014 bstrncat(sequence, "_", sizeof(sequence));
1015 bstrncat(sequence, table_name, sizeof(sequence));
1016 bstrncat(sequence, "id", sizeof(sequence));
1017 }
1018
1019 bstrncat(sequence, "_seq", sizeof(sequence));
1020 id = dbi_conn_sequence_last(db_handle_, NT_(sequence));
1021 } else {
1022 id = dbi_conn_sequence_last(db_handle_, NT_(table_name));
1023 }
1024
1025 return id;
1026 }
1027
1028 /* dbi_getisnull
1029 * like PQgetisnull
1030 * int PQgetisnull(const PGresult *res,
1031 * int row_number,
1032 * int column_number);
1033 *
1034 * use dbi_result_seek_row to search in result set
1035 */
DbiGetisnull(dbi_result * result,int row_number,int column_number)1036 static int DbiGetisnull(dbi_result *result, int row_number, int column_number) {
1037 int i;
1038
1039 if (row_number == 0) {
1040 row_number++;
1041 }
1042
1043 column_number++;
1044
1045 if (dbi_result_seek_row(result, row_number)) {
1046 i = dbi_result_field_is_null_idx(result,column_number);
1047 return i;
1048 } else {
1049 return 0;
1050 }
1051 }
1052
SqlFetchField(void)1053 SQL_FIELD *BareosDbDBI::SqlFetchField(void)
1054 {
1055 int i, j;
1056 int dbi_index;
1057 int MaxLength;
1058 int this_length;
1059 char *cbuf = NULL;
1060
1061 Dmsg0(500, "SqlFetchField starts\n");
1062
1063 if (!fields_ || fields_size_ < num_fields_) {
1064 if (fields_) {
1065 free(fields_);
1066 fields_ = NULL;
1067 }
1068 Dmsg1(500, "allocating space for %d fields\n", num_fields_);
1069 fields_ = (SQL_FIELD *)malloc(sizeof(SQL_FIELD) * num_fields_);
1070 fields_size_ = num_fields_;
1071
1072 for (i = 0; i < num_fields_; i++) {
1073 /*
1074 * num_fields is starting at 1, increment i by 1
1075 */
1076 dbi_index = i + 1;
1077 Dmsg1(500, "filling field %d\n", i);
1078 fields_[i].name = (char *)dbi_result_get_field_name(result_, dbi_index);
1079 fields_[i].type = dbi_result_get_field_type_idx(result_, dbi_index);
1080 fields_[i].flags = dbi_result_get_field_attribs_idx(result_, dbi_index);
1081
1082 /*
1083 * For a given column, find the max length.
1084 */
1085 MaxLength = 0;
1086 for (j = 0; j < num_rows_; j++) {
1087 if (DbiGetisnull(result_, j, dbi_index)) {
1088 this_length = 4; /* "NULL" */
1089 } else {
1090 cbuf = dbi_getvalue(result_, j, dbi_index);
1091 this_length = cstrlen(cbuf);
1092 /*
1093 * cbuf is always free
1094 */
1095 free(cbuf);
1096 }
1097
1098 if (MaxLength < this_length) {
1099 MaxLength = this_length;
1100 }
1101 }
1102 fields_[i].MaxLength = MaxLength;
1103
1104 Dmsg4(500, "SqlFetchField finds field '%s' has length='%d' type='%d' and IsNull=%d\n",
1105 fields_[i].name, fields_[i].MaxLength, fields_[i].type, fields_[i].flags);
1106 }
1107 }
1108
1109 /*
1110 * Increment field number for the next time around
1111 */
1112 return &fields_[field_number_++];
1113 }
1114
SqlFieldIsNotNull(int field_type)1115 bool BareosDbDBI::SqlFieldIsNotNull(int field_type)
1116 {
1117 switch (field_type) {
1118 case (1 << 0):
1119 return true;
1120 default:
1121 return false;
1122 }
1123 }
1124
SqlFieldIsNumeric(int field_type)1125 bool BareosDbDBI::SqlFieldIsNumeric(int field_type)
1126 {
1127 switch (field_type) {
1128 case 1:
1129 case 2:
1130 return true;
1131 default:
1132 return false;
1133 }
1134 }
1135
1136 /**
1137 * Escape strings so that PostgreSQL is happy on COPY
1138 *
1139 * NOTE! len is the length of the old string. Your new
1140 * string must be long enough (max 2*old+1) to hold
1141 * the escaped output.
1142 */
postgresql_copy_escape(char * dest,char * src,size_t len)1143 static char *postgresql_copy_escape(char *dest, char *src, size_t len)
1144 {
1145 /*
1146 * We have to escape \t, \n, \r, \
1147 */
1148 char c = '\0' ;
1149
1150 while (len > 0 && *src) {
1151 switch (*src) {
1152 case '\n':
1153 c = 'n';
1154 break;
1155 case '\\':
1156 c = '\\';
1157 break;
1158 case '\t':
1159 c = 't';
1160 break;
1161 case '\r':
1162 c = 'r';
1163 break;
1164 default:
1165 c = '\0' ;
1166 }
1167
1168 if (c) {
1169 *dest = '\\';
1170 dest++;
1171 *dest = c;
1172 } else {
1173 *dest = *src;
1174 }
1175
1176 len--;
1177 src++;
1178 dest++;
1179 }
1180
1181 *dest = '\0';
1182 return dest;
1183 }
1184
1185 /**
1186 * This can be a bit strang but is the one way to do
1187 *
1188 * Returns true if OK
1189 * false if failed
1190 */
SqlBatchStart(JobControlRecord * jcr)1191 bool BareosDbDBI::SqlBatchStart(JobControlRecord *jcr)
1192 {
1193 bool retval = true;
1194 const char *query = "COPY batch FROM STDIN";
1195
1196 Dmsg0(500, "SqlBatchStart started\n");
1197
1198 DbLock(this);
1199 switch (db_type_) {
1200 case SQL_TYPE_MYSQL:
1201 if (!SqlQueryWithoutHandler("CREATE TEMPORARY TABLE batch ("
1202 "FileIndex integer,"
1203 "JobId integer,"
1204 "Path blob,"
1205 "Name blob,"
1206 "LStat tinyblob,"
1207 "MD5 tinyblob,"
1208 "DeltaSeq smallint)")) {
1209 Dmsg0(500, "SqlBatchStart failed\n");
1210 goto bail_out;
1211 }
1212 Dmsg0(500, "SqlBatchStart finishing\n");
1213 goto ok_out;
1214 case SQL_TYPE_POSTGRESQL:
1215 if (!SqlQueryWithoutHandler("CREATE TEMPORARY TABLE batch ("
1216 "FileIndex int,"
1217 "JobId int,"
1218 "Path varchar,"
1219 "Name varchar,"
1220 "LStat varchar,"
1221 "MD5 varchar,"
1222 "DeltaSeq int)")) {
1223 Dmsg0(500, "SqlBatchStart failed\n");
1224 goto bail_out;
1225 }
1226
1227 /*
1228 * We are starting a new query. reset everything.
1229 */
1230 num_rows_ = -1;
1231 row_number_ = -1;
1232 field_number_ = -1;
1233
1234 SqlFreeResult();
1235
1236 for (int i=0; i < 10; i++) {
1237 SqlQueryWithoutHandler(query);
1238 if (result_) {
1239 break;
1240 }
1241 Bmicrosleep(5, 0);
1242 }
1243 if (!result_) {
1244 Dmsg1(50, "Query failed: %s\n", query);
1245 goto bail_out;
1246 }
1247
1248 status_ = (dbi_error_flag)dbi_conn_error(db_handle_, NULL);
1249 //status_ = DBI_ERROR_NONE;
1250
1251 if (status_ == DBI_ERROR_NONE) {
1252 /*
1253 * How many fields in the set?
1254 */
1255 num_fields_ = dbi_result_get_numfields(result_);
1256 num_rows_ = dbi_result_get_numrows(result_);
1257 status_ = (dbi_error_flag) 1;
1258 } else {
1259 Dmsg1(50, "Result status failed: %s\n", query);
1260 goto bail_out;
1261 }
1262
1263 Dmsg0(500, "SqlBatchStart finishing\n");
1264 goto ok_out;
1265 case SQL_TYPE_SQLITE3:
1266 if (!SqlQueryWithoutHandler("CREATE TEMPORARY TABLE batch ("
1267 "FileIndex integer,"
1268 "JobId integer,"
1269 "Path blob,"
1270 "Name blob,"
1271 "LStat tinyblob,"
1272 "MD5 tinyblob,"
1273 "DeltaSeq smallint)")) {
1274 Dmsg0(500, "SqlBatchStart failed\n");
1275 goto bail_out;
1276 }
1277 Dmsg0(500, "SqlBatchStart finishing\n");
1278 goto ok_out;
1279 }
1280
1281 bail_out:
1282 Mmsg1(&errmsg, _("error starting batch mode: %s"), sql_strerror());
1283 status_ = (dbi_error_flag) 0;
1284 SqlFreeResult();
1285 result_ = NULL;
1286 retval = false;
1287
1288 ok_out:
1289 DbUnlock(this);
1290 return retval;
1291 }
1292
1293 /**
1294 * Set error to something to abort operation
1295 */
SqlBatchEnd(JobControlRecord * jcr,const char * error)1296 bool BareosDbDBI::SqlBatchEnd(JobControlRecord *jcr, const char *error)
1297 {
1298 int res = 0;
1299 int count = 30;
1300 int (*custom_function)(void*, const char*) = NULL;
1301 dbi_conn_t *myconn = (dbi_conn_t *)(db_handle_);
1302
1303 Dmsg0(500, "SqlBatchStart started\n");
1304
1305 switch (db_type_) {
1306 case SQL_TYPE_MYSQL:
1307 status_ = (dbi_error_flag) 0;
1308 break;
1309 case SQL_TYPE_POSTGRESQL:
1310 custom_function = (custom_function_end_t)dbi_driver_specific_function(dbi_conn_get_driver(myconn), "PQputCopyEnd");
1311
1312 do {
1313 res = (*custom_function)(myconn->connection, error);
1314 } while (res == 0 && --count > 0);
1315
1316 if (res == 1) {
1317 Dmsg0(500, "ok\n");
1318 status_ = (dbi_error_flag) 1;
1319 }
1320
1321 if (res <= 0) {
1322 Dmsg0(500, "we failed\n");
1323 status_ = (dbi_error_flag) 0;
1324 //Mmsg1(&errmsg, _("error ending batch mode: %s"), PQerrorMessage(myconn));
1325 }
1326 break;
1327 case SQL_TYPE_SQLITE3:
1328 status_ = (dbi_error_flag) 0;
1329 break;
1330 }
1331
1332 Dmsg0(500, "SqlBatchStart finishing\n");
1333
1334 return true;
1335 }
1336
1337 /**
1338 * This function is big and use a big switch.
1339 * In near future is better split in small functions
1340 * and refactory.
1341 */
SqlBatchInsert(JobControlRecord * jcr,AttributesDbRecord * ar)1342 bool BareosDbDBI::SqlBatchInsert(JobControlRecord *jcr, AttributesDbRecord *ar)
1343 {
1344 int res;
1345 int count=30;
1346 dbi_conn_t *myconn = (dbi_conn_t *)(db_handle_);
1347 int (*custom_function)(void*, const char*, int) = NULL;
1348 char* (*custom_function_error)(void*) = NULL;
1349 size_t len;
1350 char *digest;
1351 char ed1[50];
1352
1353 Dmsg0(500, "SqlBatchStart started \n");
1354
1355 esc_name = CheckPoolMemorySize(esc_name, fnl*2+1);
1356 esc_path = CheckPoolMemorySize(esc_path, pnl*2+1);
1357
1358 if (ar->Digest == NULL || ar->Digest[0] == 0) {
1359 digest = "";
1360 } else {
1361 digest = ar->Digest;
1362 }
1363
1364 switch (db_type_) {
1365 case SQL_TYPE_MYSQL:
1366 db_escape_string(jcr, esc_name, fname, fnl);
1367 db_escape_string(jcr, esc_path, path, pnl);
1368 len = Mmsg(cmd, "INSERT INTO batch VALUES "
1369 "(%u,%s,'%s','%s','%s','%s',%u)",
1370 ar->FileIndex, edit_int64(ar->JobId,ed1), esc_path,
1371 esc_name, ar->attr, digest, ar->DeltaSeq);
1372
1373 if (!SqlQueryWithoutHandler(cmd))
1374 {
1375 Dmsg0(500, "SqlBatchStart failed\n");
1376 goto bail_out;
1377 }
1378
1379 Dmsg0(500, "SqlBatchStart finishing\n");
1380
1381 return true;
1382 break;
1383 case SQL_TYPE_POSTGRESQL:
1384 postgresql_copy_escape(esc_name, fname, fnl);
1385 postgresql_copy_escape(esc_path, path, pnl);
1386 len = Mmsg(cmd, "%u\t%s\t%s\t%s\t%s\t%s\t%u\n",
1387 ar->FileIndex, edit_int64(ar->JobId, ed1), esc_path,
1388 esc_name, ar->attr, digest, ar->DeltaSeq);
1389
1390 /*
1391 * libdbi don't support CopyData and we need call a postgresql
1392 * specific function to do this work
1393 */
1394 Dmsg2(500, "SqlBatchInsert :\n %s \ncmd_size: %d",cmd, len);
1395 custom_function = (custom_function_insert_t)dbi_driver_specific_function(dbi_conn_get_driver(myconn),"PQputCopyData");
1396 if (custom_function != NULL) {
1397 do {
1398 res = (*custom_function)(myconn->connection, cmd, len);
1399 } while (res == 0 && --count > 0);
1400
1401 if (res == 1) {
1402 Dmsg0(500, "ok\n");
1403 changes++;
1404 status_ = (dbi_error_flag) 1;
1405 }
1406
1407 if (res <= 0) {
1408 Dmsg0(500, "SqlBatchInsert failed\n");
1409 goto bail_out;
1410 }
1411
1412 Dmsg0(500, "SqlBatchInsert finishing\n");
1413 return true;
1414 } else {
1415 /*
1416 * Ensure to detect a PQerror
1417 */
1418 custom_function_error = (custom_function_error_t)dbi_driver_specific_function(dbi_conn_get_driver(myconn), "PQerrorMessage");
1419 Dmsg1(500, "SqlBatchInsert failed\n PQerrorMessage: %s", (*custom_function_error)(myconn->connection));
1420 goto bail_out;
1421 }
1422 break;
1423 case SQL_TYPE_SQLITE3:
1424 db_escape_string(jcr, esc_name, fname, fnl);
1425 db_escape_string(jcr, esc_path, path, pnl);
1426 len = Mmsg(cmd, "INSERT INTO batch VALUES "
1427 "(%u,%s,'%s','%s','%s','%s',%u)",
1428 ar->FileIndex, edit_int64(ar->JobId,ed1), esc_path,
1429 esc_name, ar->attr, digest, ar->DeltaSeq);
1430
1431 if (!SqlQueryWithoutHandler(cmd))
1432 {
1433 Dmsg0(500, "SqlBatchInsert failed\n");
1434 goto bail_out;
1435 }
1436
1437 Dmsg0(500, "SqlBatchInsert finishing\n");
1438
1439 return true;
1440 break;
1441 }
1442
1443 bail_out:
1444 Mmsg1(&errmsg, _("error inserting batch mode: %s"), sql_strerror());
1445 status_ = (dbi_error_flag) 0;
1446 SqlFreeResult();
1447 return false;
1448 }
1449
1450 /**
1451 * Initialize database data structure. In principal this should
1452 * never have errors, or it is really fatal.
1453 */
1454 #ifdef HAVE_DYNAMIC_CATS_BACKENDS
backend_instantiate(JobControlRecord * jcr,const char * db_driver,const char * db_name,const char * db_user,const char * db_password,const char * db_address,int db_port,const char * db_socket,bool mult_db_connections,bool disable_batch_insert,bool try_reconnect,bool exit_on_fatal,bool need_private)1455 extern "C" BareosDb *backend_instantiate(JobControlRecord *jcr,
1456 const char *db_driver,
1457 const char *db_name,
1458 const char *db_user,
1459 const char *db_password,
1460 const char *db_address,
1461 int db_port,
1462 const char *db_socket,
1463 bool mult_db_connections,
1464 bool disable_batch_insert,
1465 bool try_reconnect,
1466 bool exit_on_fatal,
1467 bool need_private)
1468 #else
1469 BareosDb *db_init_database(JobControlRecord *jcr,
1470 const char *db_driver,
1471 const char *db_name,
1472 const char *db_user,
1473 const char *db_password,
1474 const char *db_address,
1475 int db_port,
1476 const char *db_socket,
1477 bool mult_db_connections,
1478 bool disable_batch_insert,
1479 bool need_private,
1480 bool try_reconnect,
1481 bool exit_on_fatal,
1482 bool need_private)
1483 #endif
1484 {
1485 BareosDbDBI *mdb = NULL;
1486
1487 if (!db_driver) {
1488 Jmsg(jcr, M_ABORT, 0, _("Driver type not specified in Catalog resource.\n"));
1489 }
1490
1491 if (strlen(db_driver) < 5 || db_driver[3] != ':' || !bstrncasecmp(db_driver, "dbi", 3)) {
1492 Jmsg(jcr, M_ABORT, 0, _("Invalid driver type, must be \"dbi:<type>\"\n"));
1493 }
1494
1495 if (!db_user) {
1496 Jmsg(jcr, M_FATAL, 0, _("A user name for DBI must be supplied.\n"));
1497 return NULL;
1498 }
1499
1500 P(mutex); /* lock DB queue */
1501
1502 /*
1503 * Look to see if DB already open
1504 */
1505 if (db_list && !mult_db_connections && !need_private) {
1506 foreach_dlist(mdb, db_list) {
1507 if (mdb->IsPrivate()) {
1508 continue;
1509 }
1510
1511 if (mdb->MatchDatabase(db_driver, db_name, db_address, db_port)) {
1512 Dmsg1(100, "DB REopen %s\n", db_name);
1513 mdb->IncrementRefcount();
1514 goto bail_out;
1515 }
1516 }
1517 }
1518 Dmsg0(100, "db_init_database first time\n");
1519 mdb = New(BareosDbDBI(jcr,
1520 db_driver,
1521 db_name,
1522 db_user,
1523 db_password,
1524 db_address,
1525 db_port,
1526 db_socket,
1527 mult_db_connections,
1528 disable_batch_insert,
1529 try_reconnect,
1530 exit_on_fatal,
1531 need_private));
1532
1533 bail_out:
1534 V(mutex);
1535 return mdb;
1536 }
1537
1538 #ifdef HAVE_DYNAMIC_CATS_BACKENDS
flush_backend(void)1539 extern "C" void flush_backend(void)
1540 #else
1541 void DbFlushBackends(void)
1542 #endif
1543 {
1544 }
1545
1546 #endif /* HAVE_DBI */
1547