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