1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2016 Planets Communications B.V.
6    Copyright (C) 2013-2020 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  * Kern Sibbald, January 2002
25  * Major rewrite by Marco van Wieringen, January 2010 for catalog refactoring.
26  */
27 /**
28  * @file
29  * BAREOS Catalog Database routines specific to SQLite
30  */
31 
32 #include "include/bareos.h"
33 
34 #if HAVE_SQLITE3
35 
36 #  include "cats.h"
37 #  include <sqlite3.h>
38 #  include "bdb_sqlite.h"
39 
40 /* pull in the generated queries definitions */
41 #  include "sqlite_queries.inc"
42 #  include "lib/edit.h"
43 #  include "lib/berrno.h"
44 #  include "lib/dlist.h"
45 
46 /* -----------------------------------------------------------------------
47  *
48  *    SQLite dependent defines and subroutines
49  *
50  * -----------------------------------------------------------------------
51  */
52 
53 /*
54  * List of open databases
55  */
56 static dlist* db_list = NULL;
57 
58 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
59 
60 /*
61  * When using mult_db_connections = true,
62  * sqlite can be BUSY. We just need sleep a little in this case.
63  */
SqliteBusyHandler(void * arg,int calls)64 static int SqliteBusyHandler(void* arg, int calls)
65 {
66   Bmicrosleep(0, 500);
67   return 1;
68 }
69 
BareosDbSqlite(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)70 BareosDbSqlite::BareosDbSqlite(JobControlRecord* jcr,
71                                const char* db_driver,
72                                const char* db_name,
73                                const char* db_user,
74                                const char* db_password,
75                                const char* db_address,
76                                int db_port,
77                                const char* db_socket,
78                                bool mult_db_connections,
79                                bool disable_batch_insert,
80                                bool try_reconnect,
81                                bool exit_on_fatal,
82                                bool need_private)
83 {
84   /*
85    * Initialize the parent class members.
86    */
87   db_interface_type_ = SQL_INTERFACE_TYPE_SQLITE3;
88   db_type_ = SQL_TYPE_SQLITE3;
89   db_driver_ = strdup("SQLite3");
90   db_name_ = strdup(db_name);
91   if (disable_batch_insert) {
92     disabled_batch_insert_ = true;
93     have_batch_insert_ = false;
94   } else {
95     disabled_batch_insert_ = false;
96 #  if defined(USE_BATCH_FILE_INSERT)
97 #    if defined(HAVE_SQLITE3_THREADSAFE)
98     have_batch_insert_ = sqlite3_threadsafe();
99 #    else
100     have_batch_insert_ = false;
101 #    endif /* HAVE_SQLITE3_THREADSAFE */
102 #  else
103     have_batch_insert_ = false;
104 #  endif /* USE_BATCH_FILE_INSERT */
105   }
106   errmsg = GetPoolMemory(PM_EMSG); /* get error message buffer */
107   *errmsg = 0;
108   cmd = GetPoolMemory(PM_EMSG); /* get command buffer */
109   cached_path = GetPoolMemory(PM_FNAME);
110   cached_path_id = 0;
111   ref_count_ = 1;
112   fname = GetPoolMemory(PM_FNAME);
113   path = GetPoolMemory(PM_FNAME);
114   esc_name = GetPoolMemory(PM_FNAME);
115   esc_path = GetPoolMemory(PM_FNAME);
116   esc_obj = GetPoolMemory(PM_FNAME);
117   allow_transactions_ = mult_db_connections;
118   is_private_ = need_private;
119   try_reconnect_ = try_reconnect;
120   exit_on_fatal_ = exit_on_fatal;
121 
122   /*
123    * Initialize the private members.
124    */
125   db_handle_ = NULL;
126   result_ = NULL;
127   lowlevel_errmsg_ = NULL;
128 
129   /*
130    * Put the db in the list.
131    */
132   if (db_list == NULL) { db_list = new dlist(this, &this->link_); }
133   db_list->append(this);
134 
135   /* make the queries available using the queries variable from the parent class
136    */
137   queries = query_definitions;
138 }
139 
~BareosDbSqlite()140 BareosDbSqlite::~BareosDbSqlite() {}
141 
142 /**
143  * Now actually open the database.  This can generate errors,
144  * which are returned in the errmsg
145  *
146  * DO NOT close the database or delete mdb here !!!!
147  */
OpenDatabase(JobControlRecord * jcr)148 bool BareosDbSqlite::OpenDatabase(JobControlRecord* jcr)
149 {
150   bool retval = false;
151   char* db_path;
152   int len;
153   struct stat statbuf;
154   int status;
155   int errstat;
156   int retry = 0;
157 
158   P(mutex);
159   if (connected_) {
160     retval = true;
161     goto bail_out;
162   }
163 
164   if ((errstat = RwlInit(&lock_)) != 0) {
165     BErrNo be;
166     Mmsg1(errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
167           be.bstrerror(errstat));
168     goto bail_out;
169   }
170 
171   /*
172    * Open the database
173    */
174   len = strlen(working_directory) + strlen(db_name_) + 5;
175   db_path = (char*)malloc(len);
176   strcpy(db_path, working_directory);
177   strcat(db_path, "/");
178   strcat(db_path, db_name_);
179   strcat(db_path, ".db");
180   if (stat(db_path, &statbuf) != 0) {
181     Mmsg1(errmsg, _("Database %s does not exist, please create it.\n"),
182           db_path);
183     free(db_path);
184     goto bail_out;
185   }
186 
187   for (db_handle_ = NULL; !db_handle_ && retry++ < 10;) {
188     status = sqlite3_open(db_path, &db_handle_);
189     if (status != SQLITE_OK) {
190       lowlevel_errmsg_ = (char*)sqlite3_errmsg(db_handle_);
191       sqlite3_close(db_handle_);
192       db_handle_ = NULL;
193     } else {
194       lowlevel_errmsg_ = NULL;
195     }
196 
197     Dmsg0(300, "sqlite_open\n");
198     if (!db_handle_) { Bmicrosleep(1, 0); }
199   }
200   if (db_handle_ == NULL) {
201     Mmsg2(errmsg, _("Unable to open Database=%s. ERR=%s\n"), db_path,
202           lowlevel_errmsg_ ? lowlevel_errmsg_ : _("unknown"));
203     free(db_path);
204     goto bail_out;
205   }
206   connected_ = true;
207   free(db_path);
208 
209   /*
210    * Set busy handler to wait when we use mult_db_connections = true
211    */
212   sqlite3_busy_handler(db_handle_, SqliteBusyHandler, NULL);
213 
214 #  if defined(SQLITE3_INIT_QUERY)
215   SqlQueryWithoutHandler(SQLITE3_INIT_QUERY);
216 #  endif
217 
218   if (!CheckTablesVersion(jcr)) { goto bail_out; }
219 
220   retval = true;
221 
222 bail_out:
223   V(mutex);
224   return retval;
225 }
226 
CloseDatabase(JobControlRecord * jcr)227 void BareosDbSqlite::CloseDatabase(JobControlRecord* jcr)
228 {
229   if (connected_) { EndTransaction(jcr); }
230   P(mutex);
231   ref_count_--;
232   if (ref_count_ == 0) {
233     if (connected_) { SqlFreeResult(); }
234     db_list->remove(this);
235     if (connected_ && db_handle_) { sqlite3_close(db_handle_); }
236     if (RwlIsInit(&lock_)) { RwlDestroy(&lock_); }
237     FreePoolMemory(errmsg);
238     FreePoolMemory(cmd);
239     FreePoolMemory(cached_path);
240     FreePoolMemory(fname);
241     FreePoolMemory(path);
242     FreePoolMemory(esc_name);
243     FreePoolMemory(esc_path);
244     FreePoolMemory(esc_obj);
245     if (db_driver_) { free(db_driver_); }
246     if (db_name_) { free(db_name_); }
247     delete this;
248     if (db_list->size() == 0) {
249       delete db_list;
250       db_list = NULL;
251     }
252   }
253   V(mutex);
254 }
255 
ValidateConnection(void)256 bool BareosDbSqlite::ValidateConnection(void)
257 {
258   bool retval;
259 
260   DbLock(this);
261   if (SqlQueryWithoutHandler("SELECT 1", true)) {
262     SqlFreeResult();
263     retval = true;
264     goto bail_out;
265   } else {
266     retval = false;
267     goto bail_out;
268   }
269 
270 bail_out:
271   DbUnlock(this);
272   return retval;
273 }
274 
ThreadCleanup(void)275 void BareosDbSqlite::ThreadCleanup(void) { sqlite3_thread_cleanup(); }
276 
277 /**
278  * Start a transaction. This groups inserts and makes things
279  * much more efficient. Usually started when inserting
280  * file attributes.
281  */
StartTransaction(JobControlRecord * jcr)282 void BareosDbSqlite::StartTransaction(JobControlRecord* jcr)
283 {
284   if (!jcr->attr) { jcr->attr = GetPoolMemory(PM_FNAME); }
285 
286   if (!jcr->ar) {
287     jcr->ar = (AttributesDbRecord*)malloc(sizeof(AttributesDbRecord));
288     jcr->ar->Digest = NULL;
289   }
290 
291   if (!allow_transactions_) { return; }
292 
293   DbLock(this);
294   /*
295    * Allow only 10,000 changes per transaction
296    */
297   if (transaction_ && changes > 10000) { EndTransaction(jcr); }
298   if (!transaction_) {
299     SqlQueryWithoutHandler("BEGIN"); /* begin transaction */
300     Dmsg0(400, "Start SQLite transaction\n");
301     transaction_ = true;
302   }
303   DbUnlock(this);
304 }
305 
EndTransaction(JobControlRecord * jcr)306 void BareosDbSqlite::EndTransaction(JobControlRecord* jcr)
307 {
308   if (jcr && jcr->cached_attribute) {
309     Dmsg0(400, "Flush last cached attribute.\n");
310     if (!CreateAttributesRecord(jcr, jcr->ar)) {
311       Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), strerror());
312     }
313     jcr->cached_attribute = false;
314   }
315 
316   if (!allow_transactions_) { return; }
317 
318   DbLock(this);
319   if (transaction_) {
320     SqlQueryWithoutHandler("COMMIT"); /* end transaction */
321     transaction_ = false;
322     Dmsg1(400, "End SQLite transaction changes=%d\n", changes);
323   }
324   changes = 0;
325   DbUnlock(this);
326 }
327 
328 struct rh_data {
329   BareosDbSqlite* mdb;
330   DB_RESULT_HANDLER* ResultHandler;
331   void* ctx;
332   bool initialized;
333 };
334 
335 /**
336  * Convert SQLite's callback into BAREOS DB callback
337  */
SqliteResultHandler(void * arh_data,int num_fields,char ** rows,char ** col_names)338 static int SqliteResultHandler(void* arh_data,
339                                int num_fields,
340                                char** rows,
341                                char** col_names)
342 {
343   struct rh_data* rh_data = (struct rh_data*)arh_data;
344 
345   /*
346    * The SqlQueryWithHandler doesn't have access to results_,
347    * so if we wan't to get fields information, we need to use col_names
348    */
349   if (!rh_data->initialized) {
350     rh_data->mdb->SetColumnNames(col_names, num_fields);
351     rh_data->initialized = true;
352   }
353   if (rh_data->ResultHandler) {
354     (*(rh_data->ResultHandler))(rh_data->ctx, num_fields, rows);
355   }
356 
357   return 0;
358 }
359 
360 /**
361  * Submit a general SQL command (cmd), and for each row returned,
362  * the ResultHandler is called with the ctx.
363  */
SqlQueryWithHandler(const char * query,DB_RESULT_HANDLER * ResultHandler,void * ctx)364 bool BareosDbSqlite::SqlQueryWithHandler(const char* query,
365                                          DB_RESULT_HANDLER* ResultHandler,
366                                          void* ctx)
367 {
368   bool retval = false;
369   int status;
370   struct rh_data rh_data;
371 
372   Dmsg1(500, "SqlQueryWithHandler starts with '%s'\n", query);
373 
374   DbLock(this);
375   if (lowlevel_errmsg_) {
376     sqlite3_free(lowlevel_errmsg_);
377     lowlevel_errmsg_ = NULL;
378   }
379   SqlFreeResult();
380 
381   rh_data.ctx = ctx;
382   rh_data.mdb = this;
383   rh_data.initialized = false;
384   rh_data.ResultHandler = ResultHandler;
385 
386   status = sqlite3_exec(db_handle_, query, SqliteResultHandler, (void*)&rh_data,
387                         &lowlevel_errmsg_);
388 
389   if (status != SQLITE_OK) {
390     Mmsg(errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror());
391     Dmsg0(500, "SqlQueryWithHandler finished\n");
392     goto bail_out;
393   }
394   Dmsg0(500, "db_sql_query finished\n");
395   SqlFreeResult();
396   retval = true;
397 
398 bail_out:
399   DbUnlock(this);
400   return retval;
401 }
402 
403 /**
404  * Submit a sqlite query and retrieve all the data
405  */
SqlQueryWithoutHandler(const char * query,int flags)406 bool BareosDbSqlite::SqlQueryWithoutHandler(const char* query, int flags)
407 {
408   int status;
409   bool retval = false;
410 
411   Dmsg1(500, "SqlQueryWithoutHandler starts with '%s'\n", query);
412 
413   SqlFreeResult();
414   if (lowlevel_errmsg_) {
415     sqlite3_free(lowlevel_errmsg_);
416     lowlevel_errmsg_ = NULL;
417   }
418 
419   status = sqlite3_get_table(db_handle_, (char*)query, &result_, &num_rows_,
420                              &num_fields_, &lowlevel_errmsg_);
421 
422   row_number_ = 0;   /* no row fetched */
423   if (status != 0) { /* something went wrong */
424     num_rows_ = num_fields_ = 0;
425     Dmsg0(500, "SqlQueryWithoutHandler finished\n");
426   } else {
427     Dmsg0(500, "SqlQueryWithoutHandler finished\n");
428     retval = true;
429   }
430   return retval;
431 }
432 
SqlFreeResult(void)433 void BareosDbSqlite::SqlFreeResult(void)
434 {
435   DbLock(this);
436   if (fields_) {
437     free(fields_);
438     fields_ = NULL;
439   }
440   if (result_) {
441     sqlite3_free_table(result_);
442     result_ = NULL;
443   }
444   col_names_ = NULL;
445   num_rows_ = num_fields_ = 0;
446   DbUnlock(this);
447 }
448 
449 /**
450  * Fetch one row at a time
451  */
SqlFetchRow(void)452 SQL_ROW BareosDbSqlite::SqlFetchRow(void)
453 {
454   if (!result_ || (row_number_ >= num_rows_)) { return NULL; }
455   row_number_++;
456   return &result_[num_fields_ * row_number_];
457 }
458 
sql_strerror(void)459 const char* BareosDbSqlite::sql_strerror(void)
460 {
461   return lowlevel_errmsg_ ? lowlevel_errmsg_ : "unknown";
462 }
463 
SqlDataSeek(int row)464 void BareosDbSqlite::SqlDataSeek(int row)
465 {
466   /*
467    * Set the row number to be returned on the next call to sql_fetch_row
468    */
469   row_number_ = row;
470 }
471 
SqlAffectedRows(void)472 int BareosDbSqlite::SqlAffectedRows(void)
473 {
474   return sqlite3_changes(db_handle_);
475 }
476 
SqlInsertAutokeyRecord(const char * query,const char * table_name)477 uint64_t BareosDbSqlite::SqlInsertAutokeyRecord(const char* query,
478                                                 const char* table_name)
479 {
480   /*
481    * First execute the insert query and then retrieve the currval.
482    */
483   if (!SqlQueryWithoutHandler(query)) { return 0; }
484 
485   num_rows_ = SqlAffectedRows();
486   if (num_rows_ != 1) { return 0; }
487 
488   changes++;
489 
490   return sqlite3_last_insert_rowid(db_handle_);
491 }
492 
SqlFetchField(void)493 SQL_FIELD* BareosDbSqlite::SqlFetchField(void)
494 {
495   int i, j, len;
496 
497   /* We are in the middle of a db_sql_query and we want to get fields info */
498   if (col_names_ != NULL) {
499     if (num_fields_ > field_number_) {
500       sql_field_.name = col_names_[field_number_];
501       /* We don't have the maximum field length, so we can use 80 as
502        * estimation.
503        */
504       len = MAX(cstrlen(sql_field_.name), 80 / num_fields_);
505       sql_field_.max_length = len;
506 
507       field_number_++;
508       sql_field_.type = 0;  /* not numeric */
509       sql_field_.flags = 1; /* not null */
510       return &sql_field_;
511     } else { /* too much fetch_field() */
512       return NULL;
513     }
514   }
515 
516   /* We are after a SqlQuery() that stores the result in results_ */
517   if (!fields_ || fields_size_ < num_fields_) {
518     if (fields_) {
519       free(fields_);
520       fields_ = NULL;
521     }
522     Dmsg1(500, "allocating space for %d fields\n", num_fields_);
523     fields_ = (SQL_FIELD*)malloc(sizeof(SQL_FIELD) * num_fields_);
524     fields_size_ = num_fields_;
525 
526     for (i = 0; i < num_fields_; i++) {
527       Dmsg1(500, "filling field %d\n", i);
528       fields_[i].name = result_[i];
529       fields_[i].max_length = cstrlen(fields_[i].name);
530       for (j = 1; j <= num_rows_; j++) {
531         if (result_[i + num_fields_ * j]) {
532           len = (uint32_t)cstrlen(result_[i + num_fields_ * j]);
533         } else {
534           len = 0;
535         }
536         if (len > fields_[i].max_length) { fields_[i].max_length = len; }
537       }
538       fields_[i].type = 0;
539       fields_[i].flags = 1; /* not null */
540 
541       Dmsg4(500,
542             "SqlFetchField finds field '%s' has length='%d' type='%d' and "
543             "IsNull=%d\n",
544             fields_[i].name, fields_[i].max_length, fields_[i].type,
545             fields_[i].flags);
546     }
547   }
548 
549   /*
550    * Increment field number for the next time around
551    */
552   return &fields_[field_number_++];
553 }
554 
SqlFieldIsNotNull(int field_type)555 bool BareosDbSqlite::SqlFieldIsNotNull(int field_type)
556 {
557   switch (field_type) {
558     case 1:
559       return true;
560     default:
561       return false;
562   }
563 }
564 
SqlFieldIsNumeric(int field_type)565 bool BareosDbSqlite::SqlFieldIsNumeric(int field_type)
566 {
567   switch (field_type) {
568     case 1:
569       return true;
570     default:
571       return false;
572   }
573 }
574 
575 /**
576  * Returns true if OK
577  *         false if failed
578  */
SqlBatchStartFileTable(JobControlRecord * jcr)579 bool BareosDbSqlite::SqlBatchStartFileTable(JobControlRecord* jcr)
580 {
581   bool retval;
582 
583   DbLock(this);
584   retval = SqlQueryWithoutHandler(
585       "CREATE TEMPORARY TABLE batch ("
586       "FileIndex integer,"
587       "JobId integer,"
588       "Path blob,"
589       "Name blob,"
590       "LStat tinyblob,"
591       "MD5 tinyblob,"
592       "DeltaSeq integer,"
593       "Fhinfo TEXT,"
594       "Fhnode TEXT "
595       ")");
596   DbUnlock(this);
597 
598   return retval;
599 }
600 
601 /* set error to something to abort operation */
602 /**
603  * Returns true if OK
604  *         false if failed
605  */
SqlBatchEndFileTable(JobControlRecord * jcr,const char * error)606 bool BareosDbSqlite::SqlBatchEndFileTable(JobControlRecord* jcr,
607                                           const char* error)
608 {
609   status_ = 0;
610 
611   return true;
612 }
613 
614 /**
615  * Returns true if OK
616  *         false if failed
617  */
SqlBatchInsertFileTable(JobControlRecord * jcr,AttributesDbRecord * ar)618 bool BareosDbSqlite::SqlBatchInsertFileTable(JobControlRecord* jcr,
619                                              AttributesDbRecord* ar)
620 {
621   const char* digest;
622   char ed1[50], ed2[50], ed3[50];
623 
624   esc_name = CheckPoolMemorySize(esc_name, fnl * 2 + 1);
625   EscapeString(jcr, esc_name, fname, fnl);
626 
627   esc_path = CheckPoolMemorySize(esc_path, pnl * 2 + 1);
628   EscapeString(jcr, esc_path, path, pnl);
629 
630   if (ar->Digest == NULL || ar->Digest[0] == 0) {
631     digest = "0";
632   } else {
633     digest = ar->Digest;
634   }
635 
636   Mmsg(cmd,
637        "INSERT INTO batch VALUES "
638        "(%u,%s,'%s','%s','%s','%s',%u,'%s','%s')",
639        ar->FileIndex, edit_int64(ar->JobId, ed1), esc_path, esc_name, ar->attr,
640        digest, ar->DeltaSeq, edit_uint64(ar->Fhinfo, ed2),
641        edit_uint64(ar->Fhnode, ed3));
642 
643   return SqlQueryWithoutHandler(cmd);
644 }
645 
SqlCopyStart(const std::string &,const std::vector<std::string> &)646 bool BareosDbSqlite::SqlCopyStart(
647     const std::string& /*table_name*/,
648     const std::vector<std::string>& /*column_names*/)
649 {
650   return false;
651 }
652 
SqlCopyInsert(const std::vector<DatabaseField> &)653 bool BareosDbSqlite::SqlCopyInsert(
654     const std::vector<DatabaseField>& /* data_fields */)
655 {
656   return false;
657 }
658 
SqlCopyEnd()659 bool BareosDbSqlite::SqlCopyEnd() { return false; }
660 
661 /**
662  * Initialize database data structure. In principal this should
663  * never have errors, or it is really fatal.
664  */
665 #  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)666 extern "C" BareosDb* backend_instantiate(JobControlRecord* jcr,
667                                          const char* db_driver,
668                                          const char* db_name,
669                                          const char* db_user,
670                                          const char* db_password,
671                                          const char* db_address,
672                                          int db_port,
673                                          const char* db_socket,
674                                          bool mult_db_connections,
675                                          bool disable_batch_insert,
676                                          bool try_reconnect,
677                                          bool exit_on_fatal,
678                                          bool need_private)
679 #  else
680 BareosDb* db_init_database(JobControlRecord* jcr,
681                            const char* db_driver,
682                            const char* db_name,
683                            const char* db_user,
684                            const char* db_password,
685                            const char* db_address,
686                            int db_port,
687                            const char* db_socket,
688                            bool mult_db_connections,
689                            bool disable_batch_insert,
690                            bool try_reconnect,
691                            bool exit_on_fatal,
692                            bool need_private)
693 #  endif
694 {
695   BareosDb* mdb = NULL;
696 
697   P(mutex); /* lock DB queue */
698 
699   /*
700    * Look to see if DB already open
701    */
702   if (db_list && !mult_db_connections && !need_private) {
703     foreach_dlist (mdb, db_list) {
704       if (mdb->IsPrivate()) { continue; }
705 
706       if (mdb->MatchDatabase(db_driver, db_name, db_address, db_port)) {
707         Dmsg1(300, "DB REopen %s\n", db_name);
708         mdb->IncrementRefcount();
709         goto bail_out;
710       }
711     }
712   }
713   Dmsg0(300, "db_init_database first time\n");
714   mdb = new BareosDbSqlite(jcr, db_driver, db_name, db_user, db_password,
715                            db_address, db_port, db_socket, mult_db_connections,
716                            disable_batch_insert, try_reconnect, exit_on_fatal,
717                            need_private);
718 
719 bail_out:
720   V(mutex);
721   return mdb;
722 }
723 
724 #  ifdef HAVE_DYNAMIC_CATS_BACKENDS
flush_backend(void)725 extern "C" void flush_backend(void)
726 #  else
727 void DbFlushBackends(void)
728 #  endif
729 {
730 }
731 
732 #endif /* HAVE_SQLITE3 */
733