]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql.c
ebl Add code to get more information after a violent signal.
[bacula/bacula] / bacula / src / cats / sql.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU 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    General Public License for more details.
17
18    You should have received a copy of the GNU 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    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Bacula Catalog Database interface routines
30  *
31  *     Almost generic set of SQL database interface routines
32  *      (with a little more work)
33  *     SQL engine specific routines are in mysql.c, postgresql.c,
34  *       sqlite.c, ...
35  *
36  *    Kern Sibbald, March 2000
37  *
38  *    Version $Id$
39  */
40
41 /* The following is necessary so that we do not include
42  * the dummy external definition of B_DB.
43  */
44 #define __SQL_C                       /* indicate that this is sql.c */
45
46 #include "bacula.h"
47 #include "cats.h"
48
49 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI
50
51 uint32_t bacula_db_version = 0;
52
53 int db_type = -1;        /* SQL engine type index */
54
55 /* Forward referenced subroutines */
56 void print_dashes(B_DB *mdb);
57 void print_result(B_DB *mdb);
58
59 B_DB *db_init(JCR *jcr, const char *db_driver, const char *db_name, const char *db_user,
60               const char *db_password, const char *db_address, int db_port,
61               const char *db_socket, int mult_db_connections)
62 {
63 #ifdef HAVE_DBI
64    char *p;
65    if (!db_driver) {
66       Jmsg0(jcr, M_ABORT, 0, _("Driver type not specified in Catalog resource.\n"));
67    }
68    if (strlen(db_driver) < 5 || db_driver[3] != ':' || strncasecmp(db_driver, "dbi", 3) != 0) {
69       Jmsg0(jcr, M_ABORT, 0, _("Invalid driver type, must be \"dbi:<type>\"\n"));
70    }
71    p = (char *)(db_driver + 4);
72    if (strcasecmp(p, "mysql") == 0) {
73       db_type = SQL_TYPE_MYSQL;
74    } else if (strcasecmp(p, "postgresql") == 0) {
75       db_type = SQL_TYPE_POSTGRESQL;
76    } else if (strcasecmp(p, "sqlite") == 0) {
77       db_type = SQL_TYPE_SQLITE;
78    } else if (strcasecmp(p, "sqlite3") == 0) {
79       db_type = SQL_TYPE_SQLITE3;
80    } else {
81       Jmsg1(jcr, M_ABORT, 0, _("Unknown database type: %s\n"), p);
82    }
83 #elif HAVE_MYSQL
84    db_type = SQL_TYPE_MYSQL;
85 #elif HAVE_POSTGRESQL
86    db_type = SQL_TYPE_POSTGRESQL;
87 #elif HAVE_SQLITE
88    db_type = SQL_TYPE_SQLITE;
89 #elif HAVE_SQLITE3
90    db_type = SQL_TYPE_SQLITE3;
91 #endif
92
93    return db_init_database(jcr, db_name, db_user, db_password, db_address,
94              db_port, db_socket, mult_db_connections);
95 }
96
97 dbid_list::dbid_list()
98 {
99    memset(this, 0, sizeof(dbid_list));
100    max_ids = 1000;
101    DBId = (DBId_t *)malloc(max_ids * sizeof(DBId_t));
102    num_ids = num_seen = tot_ids = 0;
103    PurgedFiles = NULL;
104 }
105
106 dbid_list::~dbid_list()
107 {
108    free(DBId);
109 }
110
111
112 /*
113  * Called here to retrieve an integer from the database
114  */
115 static int int_handler(void *ctx, int num_fields, char **row)
116 {
117    uint32_t *val = (uint32_t *)ctx;
118
119    Dmsg1(800, "int_handler starts with row pointing at %x\n", row);
120
121    if (row[0]) {
122       Dmsg1(800, "int_handler finds '%s'\n", row[0]);
123       *val = str_to_int64(row[0]);
124    } else {
125       Dmsg0(800, "int_handler finds zero\n");
126       *val = 0;
127    }
128    Dmsg0(800, "int_handler finishes\n");
129    return 0;
130 }
131
132 /*
133  * Called here to retrieve a 32/64 bit integer from the database.
134  *   The returned integer will be extended to 64 bit.
135  */
136 int db_int64_handler(void *ctx, int num_fields, char **row)
137 {
138    db_int64_ctx *lctx = (db_int64_ctx *)ctx;
139
140    if (row[0]) {
141       lctx->value = str_to_int64(row[0]);
142       lctx->count++;
143    }
144    return 0;
145 }
146
147
148
149 /* NOTE!!! The following routines expect that the
150  *  calling subroutine sets and clears the mutex
151  */
152
153 /* Check that the tables correspond to the version we want */
154 bool check_tables_version(JCR *jcr, B_DB *mdb)
155 {
156    const char *query = "SELECT VersionId FROM Version";
157
158    bacula_db_version = 0;
159    if (!db_sql_query(mdb, query, int_handler, (void *)&bacula_db_version)) {
160       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
161       return false;
162    }
163    if (bacula_db_version != BDB_VERSION) {
164       Mmsg(mdb->errmsg, "Version error for database \"%s\". Wanted %d, got %d\n",
165           mdb->db_name, BDB_VERSION, bacula_db_version);
166       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
167       return false;
168    }
169    return true;
170 }
171
172 /* Utility routine for queries. The database MUST be locked before calling here. */
173 int
174 QueryDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
175 {
176    int status;
177
178    sql_free_result(mdb);
179    if ((status=sql_query(mdb, cmd)) != 0) {
180       m_msg(file, line, &mdb->errmsg, _("query %s failed:\n%s\n"), cmd, sql_strerror(mdb));
181       j_msg(file, line, jcr, M_FATAL, 0, "%s", mdb->errmsg);
182       if (verbose) {
183          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
184       }
185       return 0;
186    }
187
188    mdb->result = sql_store_result(mdb);
189
190    return mdb->result != NULL;
191 }
192
193 /*
194  * Utility routine to do inserts
195  * Returns: 0 on failure
196  *          1 on success
197  */
198 int
199 InsertDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
200 {
201    if (sql_query(mdb, cmd)) {
202       m_msg(file, line, &mdb->errmsg,  _("insert %s failed:\n%s\n"), cmd, sql_strerror(mdb));
203       j_msg(file, line, jcr, M_FATAL, 0, "%s", mdb->errmsg);
204       if (verbose) {
205          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
206       }
207       return 0;
208    }
209    if (mdb->have_insert_id) {
210       mdb->num_rows = sql_affected_rows(mdb);
211    } else {
212       mdb->num_rows = 1;
213    }
214    if (mdb->num_rows != 1) {
215       char ed1[30];
216       m_msg(file, line, &mdb->errmsg, _("Insertion problem: affected_rows=%s\n"),
217          edit_uint64(mdb->num_rows, ed1));
218       if (verbose) {
219          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
220       }
221       return 0;
222    }
223    mdb->changes++;
224    return 1;
225 }
226
227 /* Utility routine for updates.
228  *  Returns: 0 on failure
229  *           1 on success
230  */
231 int
232 UpdateDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
233 {
234
235    if (sql_query(mdb, cmd)) {
236       m_msg(file, line, &mdb->errmsg, _("update %s failed:\n%s\n"), cmd, sql_strerror(mdb));
237       j_msg(file, line, jcr, M_ERROR, 0, "%s", mdb->errmsg);
238       if (verbose) {
239          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
240       }
241       return 0;
242    }
243    mdb->num_rows = sql_affected_rows(mdb);
244    if (mdb->num_rows < 1) {
245       char ed1[30];
246       m_msg(file, line, &mdb->errmsg, _("Update failed: affected_rows=%s for %s\n"),
247          edit_uint64(mdb->num_rows, ed1), cmd);
248       if (verbose) {
249 //       j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
250       }
251       return 0;
252    }
253    mdb->changes++;
254    return 1;
255 }
256
257 /* Utility routine for deletes
258  *
259  * Returns: -1 on error
260  *           n number of rows affected
261  */
262 int
263 DeleteDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
264 {
265
266    if (sql_query(mdb, cmd)) {
267       m_msg(file, line, &mdb->errmsg, _("delete %s failed:\n%s\n"), cmd, sql_strerror(mdb));
268       j_msg(file, line, jcr, M_ERROR, 0, "%s", mdb->errmsg);
269       if (verbose) {
270          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
271       }
272       return -1;
273    }
274    mdb->changes++;
275    return sql_affected_rows(mdb);
276 }
277
278
279 /*
280  * Get record max. Query is already in mdb->cmd
281  *  No locking done
282  *
283  * Returns: -1 on failure
284  *          count on success
285  */
286 int get_sql_record_max(JCR *jcr, B_DB *mdb)
287 {
288    SQL_ROW row;
289    int stat = 0;
290
291    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
292       if ((row = sql_fetch_row(mdb)) == NULL) {
293          Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
294          stat = -1;
295       } else {
296          stat = str_to_int64(row[0]);
297       }
298       sql_free_result(mdb);
299    } else {
300       Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
301       stat = -1;
302    }
303    return stat;
304 }
305
306 /*
307  * Return pre-edited error message
308  */
309 char *db_strerror(B_DB *mdb)
310 {
311    return mdb->errmsg;
312 }
313
314 static void update_lock_dbg(B_DB *mdb) {
315    if (mdb->allow_transactions) { /* batch connection */
316       return;
317    }
318    if (_db_lock_recurse_count && !pthread_equal(_db_lock_threadid, pthread_self())) {
319       Dmsg2(1, "ERROR: not the same threadif %p != %p\n", _db_lock_threadid, pthread_self());
320    }
321    _db_lock_recurse_count++;
322    _db_lock_time = (utime_t) time(NULL);
323    _db_lock_threadid = pthread_self();
324 }
325
326 static void update_unlock_dbg(B_DB *mdb) {
327    if (mdb->allow_transactions) { /* batch connection */
328       return;
329    }
330    if (!pthread_equal(_db_lock_threadid, pthread_self())) {
331       Dmsg2(1, "ERROR: not the same threadid %p != %p", _db_lock_threadid, pthread_self());
332    }
333    _db_lock_recurse_count--;
334    if (!_db_lock_recurse_count) {
335       memset(&_db_lock_threadid, 0, sizeof(_db_lock_threadid));
336    }
337 }
338
339 /*
340  * Lock database, this can be called multiple times by the same
341  *   thread without blocking, but must be unlocked the number of
342  *   times it was locked.
343  */
344 void _db_lock(const char *file, int line, B_DB *mdb)
345 {
346    int errstat;
347    if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
348       berrno be;
349       e_msg(file, line, M_FATAL, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
350            errstat, be.bstrerror(errstat));
351    }
352    update_lock_dbg(mdb);
353 }
354
355 /*
356  * Unlock the database. This can be called multiple times by the
357  *   same thread up to the number of times that thread called
358  *   db_lock()/
359  */
360 void _db_unlock(const char *file, int line, B_DB *mdb)
361 {
362    int errstat;
363    update_unlock_dbg(mdb);
364    if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
365       berrno be;
366       e_msg(file, line, M_FATAL, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
367            errstat, be.bstrerror(errstat));
368    }
369 }
370
371 /*
372  * Start a transaction. This groups inserts and makes things
373  *  much more efficient. Usually started when inserting
374  *  file attributes.
375  */
376 void db_start_transaction(JCR *jcr, B_DB *mdb)
377 {
378    if (!jcr->attr) {
379       jcr->attr = get_pool_memory(PM_FNAME);
380    }
381    if (!jcr->ar) {
382       jcr->ar = (ATTR_DBR *)malloc(sizeof(ATTR_DBR));
383    }
384
385 #ifdef HAVE_SQLITE
386    if (!mdb->allow_transactions) {
387       return;
388    }
389    db_lock(mdb);
390    /* Allow only 10,000 changes per transaction */
391    if (mdb->transaction && mdb->changes > 10000) {
392       db_end_transaction(jcr, mdb);
393    }
394    if (!mdb->transaction) {
395       my_sqlite_query(mdb, "BEGIN");  /* begin transaction */
396       Dmsg0(400, "Start SQLite transaction\n");
397       mdb->transaction = 1;
398    }
399    db_unlock(mdb);
400 #endif
401
402 /*
403  * This is turned off because transactions break
404  * if multiple simultaneous jobs are run.
405  */
406 #ifdef HAVE_POSTGRESQL
407    if (!mdb->allow_transactions) {
408       return;
409    }
410    db_lock(mdb);
411    /* Allow only 25,000 changes per transaction */
412    if (mdb->transaction && mdb->changes > 25000) {
413       db_end_transaction(jcr, mdb);
414    }
415    if (!mdb->transaction) {
416       db_sql_query(mdb, "BEGIN", NULL, NULL);  /* begin transaction */
417       Dmsg0(400, "Start PosgreSQL transaction\n");
418       mdb->transaction = 1;
419    }
420    db_unlock(mdb);
421 #endif
422
423 #ifdef HAVE_DBI
424    if (db_type == SQL_TYPE_SQLITE) {
425       if (!mdb->allow_transactions) {
426          return;
427       }
428       db_lock(mdb);
429       /* Allow only 10,000 changes per transaction */
430       if (mdb->transaction && mdb->changes > 10000) {
431          db_end_transaction(jcr, mdb);
432       }
433       if (!mdb->transaction) {
434          //my_sqlite_query(mdb, "BEGIN");  /* begin transaction */
435          db_sql_query(mdb, "BEGIN", NULL, NULL);  /* begin transaction */
436          Dmsg0(400, "Start SQLite transaction\n");
437          mdb->transaction = 1;
438       }
439       db_unlock(mdb);
440    } else if (db_type == SQL_TYPE_POSTGRESQL) {
441       if (!mdb->allow_transactions) {
442          return;
443       }
444       db_lock(mdb);
445       /* Allow only 25,000 changes per transaction */
446       if (mdb->transaction && mdb->changes > 25000) {
447          db_end_transaction(jcr, mdb);
448       }
449       if (!mdb->transaction) {
450          db_sql_query(mdb, "BEGIN", NULL, NULL);  /* begin transaction */
451          Dmsg0(400, "Start PosgreSQL transaction\n");
452          mdb->transaction = 1;
453       }
454       db_unlock(mdb);
455    }
456 #endif
457 }
458
459 void db_end_transaction(JCR *jcr, B_DB *mdb)
460 {
461    /*
462     * This can be called during thread cleanup and
463     *   the db may already be closed.  So simply return.
464     */
465    if (!mdb) {
466       return;
467    }
468
469    if (jcr && jcr->cached_attribute) {
470       Dmsg0(400, "Flush last cached attribute.\n");
471       if (!db_create_file_attributes_record(jcr, mdb, jcr->ar)) {
472          Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db));
473       }
474       jcr->cached_attribute = false;
475    }
476
477 #ifdef HAVE_SQLITE
478    if (!mdb->allow_transactions) {
479       return;
480    }
481    db_lock(mdb);
482    if (mdb->transaction) {
483       my_sqlite_query(mdb, "COMMIT"); /* end transaction */
484       mdb->transaction = 0;
485       Dmsg1(400, "End SQLite transaction changes=%d\n", mdb->changes);
486    }
487    mdb->changes = 0;
488    db_unlock(mdb);
489 #endif
490
491 #ifdef HAVE_POSTGRESQL
492    if (!mdb->allow_transactions) {
493       return;
494    }
495    db_lock(mdb);
496    if (mdb->transaction) {
497       db_sql_query(mdb, "COMMIT", NULL, NULL); /* end transaction */
498       mdb->transaction = 0;
499       Dmsg1(400, "End PostgreSQL transaction changes=%d\n", mdb->changes);
500    }
501    mdb->changes = 0;
502    db_unlock(mdb);
503 #endif
504
505 #ifdef HAVE_DBI
506    if (db_type == SQL_TYPE_SQLITE) {
507       if (!mdb->allow_transactions) {
508          return;
509       }
510       db_lock(mdb);
511       if (mdb->transaction) {
512          //my_sqlite_query(mdb, "COMMIT"); /* end transaction */
513          db_sql_query(mdb, "COMMIT", NULL, NULL); /* end transaction */
514          mdb->transaction = 0;
515          Dmsg1(400, "End SQLite transaction changes=%d\n", mdb->changes);
516       }
517       mdb->changes = 0;
518       db_unlock(mdb);
519    } else if (db_type == SQL_TYPE_POSTGRESQL) {
520       if (!mdb->allow_transactions) {
521          return;
522       }
523       db_lock(mdb);
524       if (mdb->transaction) {
525          db_sql_query(mdb, "COMMIT", NULL, NULL); /* end transaction */
526          mdb->transaction = 0;
527          Dmsg1(400, "End PostgreSQL transaction changes=%d\n", mdb->changes);
528       }
529       mdb->changes = 0;
530       db_unlock(mdb);
531    }
532 #endif
533 }
534
535 /*
536  * Given a full filename, split it into its path
537  *  and filename parts. They are returned in pool memory
538  *  in the mdb structure.
539  */
540 void split_path_and_file(JCR *jcr, B_DB *mdb, const char *fname)
541 {
542    const char *p, *f;
543
544    /* Find path without the filename.
545     * I.e. everything after the last / is a "filename".
546     * OK, maybe it is a directory name, but we treat it like
547     * a filename. If we don't find a / then the whole name
548     * must be a path name (e.g. c:).
549     */
550    for (p=f=fname; *p; p++) {
551       if (IsPathSeparator(*p)) {
552          f = p;                       /* set pos of last slash */
553       }
554    }
555    if (IsPathSeparator(*f)) {                   /* did we find a slash? */
556       f++;                            /* yes, point to filename */
557    } else {                           /* no, whole thing must be path name */
558       f = p;
559    }
560
561    /* If filename doesn't exist (i.e. root directory), we
562     * simply create a blank name consisting of a single
563     * space. This makes handling zero length filenames
564     * easier.
565     */
566    mdb->fnl = p - f;
567    if (mdb->fnl > 0) {
568       mdb->fname = check_pool_memory_size(mdb->fname, mdb->fnl+1);
569       memcpy(mdb->fname, f, mdb->fnl);    /* copy filename */
570       mdb->fname[mdb->fnl] = 0;
571    } else {
572       mdb->fname[0] = 0;
573       mdb->fnl = 0;
574    }
575
576    mdb->pnl = f - fname;
577    if (mdb->pnl > 0) {
578       mdb->path = check_pool_memory_size(mdb->path, mdb->pnl+1);
579       memcpy(mdb->path, fname, mdb->pnl);
580       mdb->path[mdb->pnl] = 0;
581    } else {
582       Mmsg1(&mdb->errmsg, _("Path length is zero. File=%s\n"), fname);
583       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
584       mdb->path[0] = 0;
585       mdb->pnl = 0;
586    }
587
588    Dmsg2(500, "split path=%s file=%s\n", mdb->path, mdb->fname);
589 }
590
591 /*
592  * List dashes as part of header for listing SQL results in a table
593  */
594 void
595 list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
596 {
597    SQL_FIELD  *field;
598    int i, j;
599
600    sql_field_seek(mdb, 0);
601    send(ctx, "+");
602    for (i = 0; i < sql_num_fields(mdb); i++) {
603       field = sql_fetch_field(mdb);
604       if (!field) {
605          break;
606       }
607       for (j = 0; j < (int)field->max_length + 2; j++) {
608          send(ctx, "-");
609       }
610       send(ctx, "+");
611    }
612    send(ctx, "\n");
613 }
614
615 /*
616  * If full_list is set, we list vertically, otherwise, we
617  * list on one line horizontally.
618  */
619 void
620 list_result(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type)
621 {
622    SQL_FIELD *field;
623    SQL_ROW row;
624    int i, col_len, max_len = 0;
625    char buf[2000], ewc[30];
626
627    Dmsg0(800, "list_result starts\n");
628    if (mdb->result == NULL || sql_num_rows(mdb) == 0) {
629       send(ctx, _("No results to list.\n"));
630       return;
631    }
632
633    Dmsg1(800, "list_result starts looking at %d fields\n", sql_num_fields(mdb));
634    /* determine column display widths */
635    sql_field_seek(mdb, 0);
636    for (i = 0; i < sql_num_fields(mdb); i++) {
637       Dmsg1(800, "list_result processing field %d\n", i);
638       field = sql_fetch_field(mdb);
639       if (!field) {
640          break;
641       }
642       col_len = cstrlen(field->name);
643       if (type == VERT_LIST) {
644          if (col_len > max_len) {
645             max_len = col_len;
646          }
647       } else {
648          if (IS_NUM(field->type) && (int)field->max_length > 0) { /* fixup for commas */
649             field->max_length += (field->max_length - 1) / 3;
650          }
651          if (col_len < (int)field->max_length) {
652             col_len = field->max_length;
653          }
654          if (col_len < 4 && !IS_NOT_NULL(field->flags)) {
655             col_len = 4;                 /* 4 = length of the word "NULL" */
656          }
657          field->max_length = col_len;    /* reset column info */
658       }
659    }
660
661    Dmsg0(800, "list_result finished first loop\n");
662    if (type == VERT_LIST) {
663       goto vertical_list;
664    }
665
666    Dmsg1(800, "list_result starts second loop looking at %d fields\n", sql_num_fields(mdb));
667    list_dashes(mdb, send, ctx);
668    send(ctx, "|");
669    sql_field_seek(mdb, 0);
670    for (i = 0; i < sql_num_fields(mdb); i++) {
671       Dmsg1(800, "list_result looking at field %d\n", i);
672       field = sql_fetch_field(mdb);
673       if (!field) {
674          break;
675       }
676       bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, field->name);
677       send(ctx, buf);
678    }
679    send(ctx, "\n");
680    list_dashes(mdb, send, ctx);
681
682    Dmsg1(800, "list_result starts third loop looking at %d fields\n", sql_num_fields(mdb));
683    while ((row = sql_fetch_row(mdb)) != NULL) {
684       sql_field_seek(mdb, 0);
685       send(ctx, "|");
686       for (i = 0; i < sql_num_fields(mdb); i++) {
687          field = sql_fetch_field(mdb);
688          if (!field) {
689             break;
690          }
691          if (row[i] == NULL) {
692             bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, "NULL");
693          } else if (IS_NUM(field->type) && !jcr->gui && is_an_integer(row[i])) {
694             bsnprintf(buf, sizeof(buf), " %*s |", (int)field->max_length,
695                       add_commas(row[i], ewc));
696          } else {
697             bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, row[i]);
698          }
699          send(ctx, buf);
700       }
701       send(ctx, "\n");
702    }
703    list_dashes(mdb, send, ctx);
704    return;
705
706 vertical_list:
707
708    Dmsg1(800, "list_result starts vertical list at %d fields\n", sql_num_fields(mdb));
709    while ((row = sql_fetch_row(mdb)) != NULL) {
710       sql_field_seek(mdb, 0);
711       for (i = 0; i < sql_num_fields(mdb); i++) {
712          field = sql_fetch_field(mdb);
713          if (!field) {
714             break;
715          }
716          if (row[i] == NULL) {
717             bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL");
718          } else if (IS_NUM(field->type) && !jcr->gui && is_an_integer(row[i])) {
719             bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name,
720                 add_commas(row[i], ewc));
721          } else {
722             bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]);
723          }
724          send(ctx, buf);
725       }
726       send(ctx, "\n");
727    }
728    return;
729 }
730
731 /* 
732  * Open a new connexion to mdb catalog. This function is used
733  * by batch and accurate mode.
734  */
735 bool db_open_batch_connexion(JCR *jcr, B_DB *mdb)
736 {
737    int multi_db=false;
738
739 #ifdef HAVE_BATCH_FILE_INSERT
740    multi_db=true;               /* we force a new connexion only if batch insert is enabled */
741 #endif
742
743    if (!jcr->db_batch) {
744       jcr->db_batch = db_init_database(jcr, 
745                                       mdb->db_name, 
746                                       mdb->db_user,
747                                       mdb->db_password, 
748                                       mdb->db_address,
749                                       mdb->db_port,
750                                       mdb->db_socket,
751                                       multi_db /* multi_db = true when using batch mode */);
752       if (!jcr->db_batch) {
753          Jmsg0(jcr, M_FATAL, 0, "Could not init batch connexion");
754          return false;
755       }
756
757       if (!db_open_database(jcr, jcr->db_batch)) {
758          Mmsg2(&jcr->db_batch->errmsg,  _("Could not open database \"%s\": ERR=%s\n"),
759               jcr->db_batch->db_name, db_strerror(jcr->db_batch));
760          Jmsg1(jcr, M_FATAL, 0, "%s", jcr->db_batch->errmsg);
761          return false;
762       }      
763       Dmsg3(100, "initdb ref=%d connected=%d db=%p\n", jcr->db_batch->ref_count,
764             jcr->db_batch->connected, jcr->db_batch->db);
765
766    }
767    return true;
768 }
769
770 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/