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