1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * Bacula Catalog Database routines specific to SQLite
21  *
22  *    Written by Kern Sibbald, January 2002
23  *
24  * Note: at one point, this file was changed to class based by a certain
25  *  programmer, and other than "wrapping" in a class, which is a trivial
26  *  change for a C++ programmer, nothing substantial was done, yet all the
27  *  code was recommitted under this programmer's name.  Consequently, we
28  *  undo those changes here.
29  */
30 
31 #include "bacula.h"
32 
33 #if HAVE_SQLITE3
34 
35 #include "cats.h"
36 #include <sqlite3.h>
37 #define __BDB_SQLITE_H_ 1
38 #include "bdb_sqlite.h"
39 
40 /* -----------------------------------------------------------------------
41  *
42  *    SQLite dependent defines and subroutines
43  *
44  * -----------------------------------------------------------------------
45  */
46 
47 /* List of open databases */
48 static dlist *db_list = NULL;
49 
50 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
51 
52 /*
53  * When using mult_db_connections
54  *   sqlite can be BUSY. We just need sleep a little in this case.
55  */
my_sqlite_busy_handler(void * arg,int calls)56 static int my_sqlite_busy_handler(void *arg, int calls)
57 {
58    bmicrosleep(0, 500);
59    return 1;
60 }
61 
BDB_SQLITE()62 BDB_SQLITE::BDB_SQLITE()
63 {
64    BDB_SQLITE *mdb = this;
65 
66    if (db_list == NULL) {
67       db_list = New(dlist(mdb, &mdb->m_link));
68    }
69    mdb->m_db_driver_type = SQL_DRIVER_TYPE_SQLITE3;
70    mdb->m_db_type = SQL_TYPE_SQLITE3;
71    mdb->m_db_driver = bstrdup("SQLite3");
72 
73    mdb->errmsg = get_pool_memory(PM_EMSG); /* get error message buffer */
74    mdb->errmsg[0] = 0;
75    mdb->cmd = get_pool_memory(PM_EMSG);    /* get command buffer */
76    mdb->cached_path = get_pool_memory(PM_FNAME);
77    mdb->cached_path_id = 0;
78    mdb->m_ref_count = 1;
79    mdb->fname = get_pool_memory(PM_FNAME);
80    mdb->path = get_pool_memory(PM_FNAME);
81    mdb->esc_name = get_pool_memory(PM_FNAME);
82    mdb->esc_path = get_pool_memory(PM_FNAME);
83    mdb->esc_obj  = get_pool_memory(PM_FNAME);
84    mdb->m_use_fatal_jmsg = true;
85 
86    /* Initialize the private members. */
87    mdb->m_db_handle = NULL;
88    mdb->m_result = NULL;
89    mdb->m_sqlite_errmsg = NULL;
90 
91    db_list->append(this);
92 }
93 
~BDB_SQLITE()94 BDB_SQLITE::~BDB_SQLITE()
95 {
96 }
97 
98 /*
99  * Initialize database data structure. In principal this should
100  * never have errors, or it is really fatal.
101  */
db_init_database(JCR * 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,const char * db_ssl_mode,const char * db_ssl_key,const char * db_ssl_cert,const char * db_ssl_ca,const char * db_ssl_capath,const char * db_ssl_cipher,bool mult_db_connections,bool disable_batch_insert)102 BDB *db_init_database(JCR *jcr, const char *db_driver, const char *db_name, const char *db_user,
103                        const char *db_password, const char *db_address, int db_port, const char *db_socket,
104                        const char *db_ssl_mode, const char *db_ssl_key,
105                        const char *db_ssl_cert, const char *db_ssl_ca,
106                        const char *db_ssl_capath, const char *db_ssl_cipher,
107                        bool mult_db_connections, bool disable_batch_insert)
108 {
109    BDB_SQLITE *mdb = NULL;
110 
111    P(mutex);                          /* lock DB queue */
112    /*
113     * Look to see if DB already open
114     */
115    if (db_list && !mult_db_connections) {
116       foreach_dlist(mdb, db_list) {
117          if (mdb->bdb_match_database(db_driver, db_name, db_address, db_port)) {
118             Dmsg1(300, "DB REopen %s\n", db_name);
119             mdb->increment_refcount();
120             goto bail_out;
121          }
122       }
123    }
124    Dmsg0(300, "db_init_database first time\n");
125    mdb = New(BDB_SQLITE());
126 
127    mdb->m_db_name = bstrdup(db_name);
128    if (disable_batch_insert) {
129       mdb->m_disabled_batch_insert = true;
130       mdb->m_have_batch_insert = false;
131    } else {
132       mdb->m_disabled_batch_insert = false;
133 #ifdef USE_BATCH_FILE_INSERT
134 #ifdef HAVE_SQLITE3_THREADSAFE
135       mdb->m_have_batch_insert = sqlite3_threadsafe();
136 #else
137       mdb->m_have_batch_insert = false;
138 #endif /* HAVE_SQLITE3_THREADSAFE */
139 #else
140       mdb->m_have_batch_insert = false;
141 #endif /* USE_BATCH_FILE_INSERT */
142    }
143    mdb->m_allow_transactions = mult_db_connections;
144 
145    /* At this time, when mult_db_connections == true, this is for
146     * specific console command such as bvfs or batch mode, and we don't
147     * want to share a batch mode or bvfs. In the future, we can change
148     * the creation function to add this parameter.
149     */
150    mdb->m_dedicated = mult_db_connections;
151 
152 bail_out:
153    V(mutex);
154    return mdb;
155 }
156 
157 
158 /*
159  * Now actually open the database.  This can generate errors,
160  * which are returned in the errmsg
161  *
162  * DO NOT close the database or delete mdb here !!!!
163  */
bdb_open_database(JCR * jcr)164 bool BDB_SQLITE::bdb_open_database(JCR *jcr)
165 {
166    bool retval = false;
167    char *db_file;
168    int len;
169    struct stat statbuf;
170    int ret;
171    int errstat;
172    int retry = 0;
173    BDB_SQLITE *mdb = this;
174 
175    P(mutex);
176    if (mdb->m_connected) {
177       retval = true;
178       goto bail_out;
179    }
180 
181    if ((errstat=rwl_init(&mdb->m_lock)) != 0) {
182       berrno be;
183       Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
184             be.bstrerror(errstat));
185       goto bail_out;
186    }
187 
188    /*
189     * Open the database
190     */
191    len = strlen(working_directory) + strlen(mdb->m_db_name) + 5;
192    db_file = (char *)malloc(len);
193    strcpy(db_file, working_directory);
194    strcat(db_file, "/");
195    strcat(db_file, m_db_name);
196    strcat(db_file, ".db");
197    if (stat(db_file, &statbuf) != 0) {
198       Mmsg1(&mdb->errmsg, _("Database %s does not exist, please create it.\n"),
199          db_file);
200       free(db_file);
201       goto bail_out;
202    }
203 
204    for (mdb->m_db_handle = NULL; !mdb->m_db_handle && retry++ < 10; ) {
205       ret = sqlite3_open(db_file, &mdb->m_db_handle);
206       if (ret != SQLITE_OK) {
207          mdb->m_sqlite_errmsg = (char *)sqlite3_errmsg(mdb->m_db_handle);
208          sqlite3_close(mdb->m_db_handle);
209          mdb->m_db_handle = NULL;
210       } else {
211          mdb->m_sqlite_errmsg = NULL;
212       }
213 
214       Dmsg0(300, "sqlite_open\n");
215       if (!mdb->m_db_handle) {
216          bmicrosleep(1, 0);
217       }
218    }
219    if (mdb->m_db_handle == NULL) {
220       Mmsg2(&mdb->errmsg, _("Unable to open Database=%s. ERR=%s\n"),
221          db_file, mdb->m_sqlite_errmsg ? mdb->m_sqlite_errmsg : _("unknown"));
222       free(db_file);
223       goto bail_out;
224    }
225    mdb->m_connected = true;
226    free(db_file);
227 
228    /*
229     * Set busy handler to wait when we use mult_db_connections = true
230     */
231    sqlite3_busy_handler(mdb->m_db_handle, my_sqlite_busy_handler, NULL);
232 
233 #if defined(SQLITE3_INIT_QUERY)
234    sql_query(SQLITE3_INIT_QUERY);
235 #endif
236 
237    if (!bdb_check_version(jcr)) {
238       goto bail_out;
239    }
240 
241    retval = true;
242 
243 bail_out:
244    V(mutex);
245    return retval;
246 }
247 
bdb_close_database(JCR * jcr)248 void BDB_SQLITE::bdb_close_database(JCR *jcr)
249 {
250    BDB_SQLITE *mdb = this;
251 
252    if (mdb->m_connected) {
253       bdb_end_transaction(jcr);
254    }
255    P(mutex);
256    mdb->m_ref_count--;
257    if (mdb->m_ref_count == 0) {
258       if (mdb->m_connected) {
259          sql_free_result();
260       }
261       db_list->remove(mdb);
262       if (mdb->m_connected && mdb->m_db_handle) {
263          sqlite3_close(mdb->m_db_handle);
264       }
265       if (is_rwl_valid(&mdb->m_lock)) {
266          rwl_destroy(&mdb->m_lock);
267       }
268       free_pool_memory(mdb->errmsg);
269       free_pool_memory(mdb->cmd);
270       free_pool_memory(mdb->cached_path);
271       free_pool_memory(mdb->fname);
272       free_pool_memory(mdb->path);
273       free_pool_memory(mdb->esc_name);
274       free_pool_memory(mdb->esc_path);
275       free_pool_memory(mdb->esc_obj);
276       if (mdb->m_db_driver) {
277          free(mdb->m_db_driver);
278       }
279       if (mdb->m_db_name) {
280          free(mdb->m_db_name);
281       }
282       delete this;
283       if (db_list->size() == 0) {
284          delete db_list;
285          db_list = NULL;
286       }
287    }
288    V(mutex);
289 }
290 
bdb_thread_cleanup(void)291 void BDB_SQLITE::bdb_thread_cleanup(void)
292 {
293    sqlite3_thread_cleanup();
294 }
295 
296 /*
297  * Escape strings so SQLite is happy
298  *
299  * len is the length of the old string. Your new
300  *   string must be long enough (max 2*old+1) to hold
301  *   the escaped output.
302  */
bdb_escape_string(JCR * jcr,char * snew,char * sold,int len)303 void BDB_SQLITE::bdb_escape_string(JCR *jcr, char *snew, char *sold, int len)
304 {
305    char *n, *o;
306 
307    n = snew;
308    o = sold;
309    while (len--) {
310       switch (*o) {
311       case '\'':
312          *n++ = '\'';
313          *n++ = '\'';
314          o++;
315          break;
316       case 0:
317          *n++ = '\\';
318          *n++ = 0;
319          o++;
320          break;
321       default:
322          *n++ = *o++;
323          break;
324       }
325    }
326    *n = 0;
327 }
328 
329 /*
330  * Escape binary object so that SQLite is happy
331  * Memory is stored in BDB struct, no need to free it
332  *
333  * TODO: this should be implemented  (escape \0)
334  */
bdb_escape_object(JCR * jcr,char * old,int len)335 char *BDB_SQLITE::bdb_escape_object(JCR *jcr, char *old, int len)
336 {
337    int l;
338    int max = len*2;           /* TODO: too big, should be *4/3 */
339 
340    esc_obj = check_pool_memory_size(esc_obj, max);
341    l = bin_to_base64(esc_obj, max, old, len, true);
342    esc_obj[l] = 0;
343    ASSERT(l < max);    /* TODO: add check for l */
344 
345    return esc_obj;
346 }
347 
348 /*
349  * Unescape binary object so that SQLIte is happy
350  *
351  * TODO: need to be implemented (escape \0)
352  */
353 
bdb_unescape_object(JCR * jcr,char * from,int32_t expected_len,POOLMEM ** dest,int32_t * dest_len)354 void BDB_SQLITE::bdb_unescape_object(JCR *jcr, char *from, int32_t expected_len,
355                                      POOLMEM **dest, int32_t *dest_len)
356 {
357    if (!from) {
358       *dest[0] = 0;
359       *dest_len = 0;
360       return;
361    }
362    *dest = check_pool_memory_size(*dest, expected_len+1);
363    base64_to_bin(*dest, expected_len+1, from, strlen(from));
364    *dest_len = expected_len;
365    (*dest)[expected_len] = 0;
366 }
367 
368 /*
369  * Start a transaction. This groups inserts and makes things
370  *  more efficient. Usually started when inserting file attributes.
371  */
bdb_start_transaction(JCR * jcr)372 void BDB_SQLITE::bdb_start_transaction(JCR *jcr)
373 {
374    BDB_SQLITE *mdb = this;
375 
376    if (!jcr->attr) {
377       jcr->attr = get_pool_memory(PM_FNAME);
378    }
379    if (!jcr->ar) {
380       jcr->ar = (ATTR_DBR *)malloc(sizeof(ATTR_DBR));
381       memset(jcr->ar, 0, sizeof(ATTR_DBR));
382    }
383 
384    if (!mdb->m_allow_transactions) {
385       return;
386    }
387 
388    bdb_lock();
389    /*
390     * Allow only 10,000 changes per transaction
391     */
392    if (mdb->m_transaction && mdb->changes > 10000) {
393       bdb_end_transaction(jcr);
394    }
395    if (!mdb->m_transaction) {
396       sql_query("BEGIN");                  /* begin transaction */
397       Dmsg0(400, "Start SQLite transaction\n");
398       mdb->m_transaction = true;
399    }
400    bdb_unlock();
401 }
402 
bdb_end_transaction(JCR * jcr)403 void BDB_SQLITE::bdb_end_transaction(JCR *jcr)
404 {
405    BDB_SQLITE *mdb = this;
406    if (!mdb->m_allow_transactions) {
407       return;
408    }
409 
410    bdb_lock();
411    if (mdb->m_transaction) {
412       sql_query("COMMIT"); /* end transaction */
413       mdb->m_transaction = false;
414       Dmsg1(400, "End SQLite transaction changes=%d\n", changes);
415    }
416    mdb->changes = 0;
417    bdb_unlock();
418 }
419 
420 struct rh_data {
421    BDB_SQLITE *mdb;
422    DB_RESULT_HANDLER *result_handler;
423    void *ctx;
424    bool initialized;
425 };
426 
427 /*
428  * Convert SQLite's callback into Bacula DB callback
429  */
sqlite_result_handler(void * arh_data,int num_fields,char ** rows,char ** col_names)430 static int sqlite_result_handler(void *arh_data, int num_fields, char **rows, char **col_names)
431 {
432    struct rh_data *rh_data = (struct rh_data *)arh_data;
433 
434    /* The db_sql_query doesn't have access to m_results, so if we wan't to get
435     * fields information, we need to use col_names
436     */
437    if (!rh_data->initialized) {
438       rh_data->mdb->set_column_names(col_names, num_fields);
439       rh_data->initialized = true;
440    }
441    if (rh_data->result_handler) {
442       (*(rh_data->result_handler))(rh_data->ctx, num_fields, rows);
443    }
444 
445    return 0;
446 }
447 
448 /*
449  * Submit a general SQL command (cmd), and for each row returned,
450  *  the result_handler is called with the ctx.
451  */
bdb_sql_query(const char * query,DB_RESULT_HANDLER * result_handler,void * ctx)452 bool BDB_SQLITE::bdb_sql_query(const char *query, DB_RESULT_HANDLER *result_handler, void *ctx)
453 {
454    BDB_SQLITE *mdb = this;
455    bool retval = false;
456    int stat;
457    struct rh_data rh_data;
458 
459    Dmsg1(500, "db_sql_query starts with '%s'\n", query);
460 
461    bdb_lock();
462    mdb->errmsg[0] = 0;
463    if (mdb->m_sqlite_errmsg) {
464       sqlite3_free(mdb->m_sqlite_errmsg);
465       mdb->m_sqlite_errmsg = NULL;
466    }
467    sql_free_result();
468 
469    rh_data.ctx = ctx;
470    rh_data.mdb = this;
471    rh_data.initialized = false;
472    rh_data.result_handler = result_handler;
473 
474    stat = sqlite3_exec(m_db_handle, query, sqlite_result_handler,
475                        (void *)&rh_data, &m_sqlite_errmsg);
476 
477    if (stat != SQLITE_OK) {
478       Mmsg(mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror());
479       Dmsg0(500, "db_sql_query finished\n");
480       goto bail_out;
481    }
482    Dmsg0(500, "db_sql_query finished\n");
483    sql_free_result();
484    retval = true;
485 
486 bail_out:
487    bdb_unlock();
488    return retval;
489 }
490 
491 /*
492  * Submit a sqlite query and retrieve all the data
493  */
sql_query(const char * query,int flags)494 bool BDB_SQLITE::sql_query(const char *query, int flags)
495 {
496    int stat;
497    bool retval = false;
498    BDB_SQLITE *mdb = this;
499 
500    Dmsg1(500, "sql_query starts with '%s'\n", query);
501 
502    sql_free_result();
503    if (mdb->m_sqlite_errmsg) {
504       sqlite3_free(mdb->m_sqlite_errmsg);
505       mdb->m_sqlite_errmsg = NULL;
506    }
507 
508    stat = sqlite3_get_table(m_db_handle, (char *)query, &m_result,
509                             &m_num_rows, &m_num_fields, &m_sqlite_errmsg);
510 
511    mdb->m_row_number = 0;               /* no row fetched */
512    if (stat != 0) {                     /* something went wrong */
513       mdb->m_num_rows = mdb->m_num_fields = 0;
514       Dmsg0(500, "sql_query finished\n");
515    } else {
516       Dmsg0(500, "sql_query finished\n");
517       retval = true;
518    }
519    return retval;
520 }
521 
sql_free_result(void)522 void BDB_SQLITE::sql_free_result(void)
523 {
524    BDB_SQLITE *mdb = this;
525 
526    bdb_lock();
527    if (mdb->m_fields) {
528       free(mdb->m_fields);
529       mdb->m_fields = NULL;
530    }
531    if (mdb->m_result) {
532       sqlite3_free_table(mdb->m_result);
533       mdb->m_result = NULL;
534    }
535    mdb->m_col_names = NULL;
536    mdb->m_num_rows = mdb->m_num_fields = 0;
537    bdb_unlock();
538 }
539 
540 /*
541  * Fetch one row at a time
542  */
sql_fetch_row(void)543 SQL_ROW BDB_SQLITE::sql_fetch_row(void)
544 {
545    BDB_SQLITE *mdb = this;
546    if (!mdb->m_result || (mdb->m_row_number >= mdb->m_num_rows)) {
547       return NULL;
548    }
549    mdb->m_row_number++;
550    return &mdb->m_result[mdb->m_num_fields * mdb->m_row_number];
551 }
552 
sql_strerror(void)553 const char *BDB_SQLITE::sql_strerror(void)
554 {
555    BDB_SQLITE *mdb = this;
556    return mdb->m_sqlite_errmsg ? mdb->m_sqlite_errmsg : "unknown";
557 }
558 
sql_data_seek(int row)559 void BDB_SQLITE::sql_data_seek(int row)
560 {
561    BDB_SQLITE *mdb = this;
562    /* Set the row number to be returned on the next call to sql_fetch_row  */
563    mdb->m_row_number = row;
564 }
565 
sql_affected_rows(void)566 int BDB_SQLITE::sql_affected_rows(void)
567 {
568    BDB_SQLITE *mdb = this;
569    return sqlite3_changes(mdb->m_db_handle);
570 }
571 
sql_insert_autokey_record(const char * query,const char * table_name)572 uint64_t BDB_SQLITE::sql_insert_autokey_record(const char *query, const char *table_name)
573 {
574    BDB_SQLITE *mdb = this;
575    /* First execute the insert query and then retrieve the currval.  */
576    if (!sql_query(query)) {
577       return 0;
578    }
579 
580    mdb->m_num_rows = sql_affected_rows();
581    if (mdb->m_num_rows != 1) {
582       return 0;
583    }
584 
585    mdb->changes++;
586 
587    return sqlite3_last_insert_rowid(mdb->m_db_handle);
588 }
589 
sql_fetch_field(void)590 SQL_FIELD *BDB_SQLITE::sql_fetch_field(void)
591 {
592    BDB_SQLITE *mdb = this;
593    int i, j, len;
594 
595    /* We are in the middle of a db_sql_query and we want to get fields info */
596    if (mdb->m_col_names != NULL) {
597       if (mdb->m_num_fields > mdb->m_field_number) {
598          mdb->m_sql_field.name = mdb->m_col_names[mdb->m_field_number];
599          /* We don't have the maximum field length, so we can use 80 as
600           * estimation.
601           */
602          len = MAX(cstrlen(mdb->m_sql_field.name), 80/mdb->m_num_fields);
603          mdb->m_sql_field.max_length = len;
604 
605          mdb->m_field_number++;
606          mdb->m_sql_field.type = 0;  /* not numeric */
607          mdb->m_sql_field.flags = 1; /* not null */
608          return &mdb->m_sql_field;
609       } else {                  /* too much fetch_field() */
610          return NULL;
611       }
612    }
613 
614    /* We are after a sql_query() that stores the result in m_results */
615    if (!mdb->m_fields || mdb->m_fields_size < mdb->m_num_fields) {
616       if (mdb->m_fields) {
617          free(mdb->m_fields);
618          mdb->m_fields = NULL;
619       }
620       Dmsg1(500, "allocating space for %d fields\n", m_num_fields);
621       mdb->m_fields = (SQL_FIELD *)malloc(sizeof(SQL_FIELD) * mdb->m_num_fields);
622       mdb->m_fields_size = mdb->m_num_fields;
623 
624       for (i = 0; i < mdb->m_num_fields; i++) {
625          Dmsg1(500, "filling field %d\n", i);
626          mdb->m_fields[i].name = mdb->m_result[i];
627          mdb->m_fields[i].max_length = cstrlen(mdb->m_fields[i].name);
628          for (j = 1; j <= mdb->m_num_rows; j++) {
629             if (mdb->m_result[i + mdb->m_num_fields * j]) {
630                len = (uint32_t)cstrlen(mdb->m_result[i + mdb->m_num_fields * j]);
631             } else {
632                len = 0;
633             }
634             if (len > mdb->m_fields[i].max_length) {
635                mdb->m_fields[i].max_length = len;
636             }
637          }
638          mdb->m_fields[i].type = 0;
639          mdb->m_fields[i].flags = 1;        /* not null */
640 
641          Dmsg4(500, "sql_fetch_field finds field '%s' has length='%d' type='%d' and IsNull=%d\n",
642                mdb->m_fields[i].name, mdb->m_fields[i].max_length, mdb->m_fields[i].type, mdb->m_fields[i].flags);
643       }
644    }
645 
646    /* Increment field number for the next time around */
647    return &mdb->m_fields[mdb->m_field_number++];
648 }
649 
sql_field_is_not_null(int field_type)650 bool BDB_SQLITE::sql_field_is_not_null(int field_type)
651 {
652    if (field_type == 1) {
653       return true;
654    }
655    return false;
656 }
657 
sql_field_is_numeric(int field_type)658 bool BDB_SQLITE::sql_field_is_numeric(int field_type)
659 {
660    if (field_type == 1) {
661       return true;
662    }
663    return false;
664 }
665 
666 /*
667  * Returns true  if OK
668  *         false if failed
669  */
sql_batch_start(JCR * jcr)670 bool BDB_SQLITE::sql_batch_start(JCR *jcr)
671 {
672    bool ret;
673 
674    bdb_lock();
675    ret = sql_query("CREATE TEMPORARY TABLE batch ("
676                    "FileIndex integer,"
677                    "JobId integer,"
678                    "Path blob,"
679                    "Name blob,"
680                    "LStat tinyblob,"
681                    "MD5 tinyblob,"
682                    "DeltaSeq integer)");
683    bdb_unlock();
684 
685    return ret;
686 }
687 
688 /* Set error to something to abort operation */
689 /*
690  * Returns true  if OK
691  *         false if failed
692  */
sql_batch_end(JCR * jcr,const char * error)693 bool BDB_SQLITE::sql_batch_end(JCR *jcr, const char *error)
694 {
695    m_status = 0;
696    return true;
697 }
698 
699 /*
700  * Returns true  if OK
701  *         false if failed
702  */
sql_batch_insert(JCR * jcr,ATTR_DBR * ar)703 bool BDB_SQLITE::sql_batch_insert(JCR *jcr, ATTR_DBR *ar)
704 {
705    BDB_SQLITE *mdb = this;
706    const char *digest;
707    char ed1[50];
708 
709    mdb->esc_name = check_pool_memory_size(mdb->esc_name, mdb->fnl*2+1);
710    bdb_escape_string(jcr, mdb->esc_name, mdb->fname, mdb->fnl);
711 
712    mdb->esc_path = check_pool_memory_size(mdb->esc_path, mdb->pnl*2+1);
713    bdb_escape_string(jcr, mdb->esc_path, mdb->path, mdb->pnl);
714 
715    if (ar->Digest == NULL || ar->Digest[0] == 0) {
716       digest = "0";
717    } else {
718       digest = ar->Digest;
719    }
720 
721    Mmsg(mdb->cmd, "INSERT INTO batch VALUES "
722         "(%d,%s,'%s','%s','%s','%s',%u)",
723         ar->FileIndex, edit_int64(ar->JobId,ed1), mdb->esc_path,
724         mdb->esc_name, ar->attr, digest, ar->DeltaSeq);
725 
726    return sql_query(mdb->cmd);
727 }
728 
729 
730 #endif /* HAVE_SQLITE3 */
731