]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql.c
turn off code that does not compile
[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 {
316 #ifdef xxx
317    if (mdb->allow_transactions) { /* batch connection */
318       return;
319    }
320    if (_db_lock_recurse_count && !pthread_equal(_db_lock_threadid, pthread_self())) {
321       Dmsg2(1, "ERROR: not the same threadif %p != %p\n", _db_lock_threadid, pthread_self());
322    }
323    _db_lock_recurse_count++;
324    _db_lock_time = (utime_t) time(NULL);
325    _db_lock_threadid = pthread_self();
326 #endif
327 }
328
329 static void update_unlock_dbg(B_DB *mdb) 
330 {
331 #ifdef xxx
332    if (mdb->allow_transactions) { /* batch connection */
333       return;
334    }
335    if (!pthread_equal(_db_lock_threadid, pthread_self())) {
336       Dmsg2(1, "ERROR: not the same threadid %p != %p", _db_lock_threadid, pthread_self());
337    }
338    _db_lock_recurse_count--;
339    if (!_db_lock_recurse_count) {
340       memset(&_db_lock_threadid, 0, sizeof(_db_lock_threadid));
341    }
342 #endif
343 }
344
345 /*
346  * Lock database, this can be called multiple times by the same
347  *   thread without blocking, but must be unlocked the number of
348  *   times it was locked.
349  */
350 void _db_lock(const char *file, int line, B_DB *mdb)
351 {
352    int errstat;
353    if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
354       berrno be;
355       e_msg(file, line, M_FATAL, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
356            errstat, be.bstrerror(errstat));
357    }
358    update_lock_dbg(mdb);
359 }
360
361 /*
362  * Unlock the database. This can be called multiple times by the
363  *   same thread up to the number of times that thread called
364  *   db_lock()/
365  */
366 void _db_unlock(const char *file, int line, B_DB *mdb)
367 {
368    int errstat;
369    update_unlock_dbg(mdb);
370    if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
371       berrno be;
372       e_msg(file, line, M_FATAL, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
373            errstat, be.bstrerror(errstat));
374    }
375 }
376
377 /*
378  * Start a transaction. This groups inserts and makes things
379  *  much more efficient. Usually started when inserting
380  *  file attributes.
381  */
382 void db_start_transaction(JCR *jcr, B_DB *mdb)
383 {
384    if (!jcr->attr) {
385       jcr->attr = get_pool_memory(PM_FNAME);
386    }
387    if (!jcr->ar) {
388       jcr->ar = (ATTR_DBR *)malloc(sizeof(ATTR_DBR));
389    }
390
391 #ifdef HAVE_SQLITE
392    if (!mdb->allow_transactions) {
393       return;
394    }
395    db_lock(mdb);
396    /* Allow only 10,000 changes per transaction */
397    if (mdb->transaction && mdb->changes > 10000) {
398       db_end_transaction(jcr, mdb);
399    }
400    if (!mdb->transaction) {
401       my_sqlite_query(mdb, "BEGIN");  /* begin transaction */
402       Dmsg0(400, "Start SQLite transaction\n");
403       mdb->transaction = 1;
404    }
405    db_unlock(mdb);
406 #endif
407
408 /*
409  * This is turned off because transactions break
410  * if multiple simultaneous jobs are run.
411  */
412 #ifdef HAVE_POSTGRESQL
413    if (!mdb->allow_transactions) {
414       return;
415    }
416    db_lock(mdb);
417    /* Allow only 25,000 changes per transaction */
418    if (mdb->transaction && mdb->changes > 25000) {
419       db_end_transaction(jcr, mdb);
420    }
421    if (!mdb->transaction) {
422       db_sql_query(mdb, "BEGIN", NULL, NULL);  /* begin transaction */
423       Dmsg0(400, "Start PosgreSQL transaction\n");
424       mdb->transaction = 1;
425    }
426    db_unlock(mdb);
427 #endif
428
429 #ifdef HAVE_DBI
430    if (db_type == SQL_TYPE_SQLITE) {
431       if (!mdb->allow_transactions) {
432          return;
433       }
434       db_lock(mdb);
435       /* Allow only 10,000 changes per transaction */
436       if (mdb->transaction && mdb->changes > 10000) {
437          db_end_transaction(jcr, mdb);
438       }
439       if (!mdb->transaction) {
440          //my_sqlite_query(mdb, "BEGIN");  /* begin transaction */
441          db_sql_query(mdb, "BEGIN", NULL, NULL);  /* begin transaction */
442          Dmsg0(400, "Start SQLite transaction\n");
443          mdb->transaction = 1;
444       }
445       db_unlock(mdb);
446    } else if (db_type == SQL_TYPE_POSTGRESQL) {
447       if (!mdb->allow_transactions) {
448          return;
449       }
450       db_lock(mdb);
451       /* Allow only 25,000 changes per transaction */
452       if (mdb->transaction && mdb->changes > 25000) {
453          db_end_transaction(jcr, mdb);
454       }
455       if (!mdb->transaction) {
456          db_sql_query(mdb, "BEGIN", NULL, NULL);  /* begin transaction */
457          Dmsg0(400, "Start PosgreSQL transaction\n");
458          mdb->transaction = 1;
459       }
460       db_unlock(mdb);
461    }
462 #endif
463 }
464
465 void db_end_transaction(JCR *jcr, B_DB *mdb)
466 {
467    /*
468     * This can be called during thread cleanup and
469     *   the db may already be closed.  So simply return.
470     */
471    if (!mdb) {
472       return;
473    }
474
475    if (jcr && jcr->cached_attribute) {
476       Dmsg0(400, "Flush last cached attribute.\n");
477       if (!db_create_file_attributes_record(jcr, mdb, jcr->ar)) {
478          Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db));
479       }
480       jcr->cached_attribute = false;
481    }
482
483 #ifdef HAVE_SQLITE
484    if (!mdb->allow_transactions) {
485       return;
486    }
487    db_lock(mdb);
488    if (mdb->transaction) {
489       my_sqlite_query(mdb, "COMMIT"); /* end transaction */
490       mdb->transaction = 0;
491       Dmsg1(400, "End SQLite transaction changes=%d\n", mdb->changes);
492    }
493    mdb->changes = 0;
494    db_unlock(mdb);
495 #endif
496
497 #ifdef HAVE_POSTGRESQL
498    if (!mdb->allow_transactions) {
499       return;
500    }
501    db_lock(mdb);
502    if (mdb->transaction) {
503       db_sql_query(mdb, "COMMIT", NULL, NULL); /* end transaction */
504       mdb->transaction = 0;
505       Dmsg1(400, "End PostgreSQL transaction changes=%d\n", mdb->changes);
506    }
507    mdb->changes = 0;
508    db_unlock(mdb);
509 #endif
510
511 #ifdef HAVE_DBI
512    if (db_type == SQL_TYPE_SQLITE) {
513       if (!mdb->allow_transactions) {
514          return;
515       }
516       db_lock(mdb);
517       if (mdb->transaction) {
518          //my_sqlite_query(mdb, "COMMIT"); /* end transaction */
519          db_sql_query(mdb, "COMMIT", NULL, NULL); /* end transaction */
520          mdb->transaction = 0;
521          Dmsg1(400, "End SQLite transaction changes=%d\n", mdb->changes);
522       }
523       mdb->changes = 0;
524       db_unlock(mdb);
525    } else if (db_type == SQL_TYPE_POSTGRESQL) {
526       if (!mdb->allow_transactions) {
527          return;
528       }
529       db_lock(mdb);
530       if (mdb->transaction) {
531          db_sql_query(mdb, "COMMIT", NULL, NULL); /* end transaction */
532          mdb->transaction = 0;
533          Dmsg1(400, "End PostgreSQL transaction changes=%d\n", mdb->changes);
534       }
535       mdb->changes = 0;
536       db_unlock(mdb);
537    }
538 #endif
539 }
540
541 /*
542  * Given a full filename, split it into its path
543  *  and filename parts. They are returned in pool memory
544  *  in the mdb structure.
545  */
546 void split_path_and_file(JCR *jcr, B_DB *mdb, const char *fname)
547 {
548    const char *p, *f;
549
550    /* Find path without the filename.
551     * I.e. everything after the last / is a "filename".
552     * OK, maybe it is a directory name, but we treat it like
553     * a filename. If we don't find a / then the whole name
554     * must be a path name (e.g. c:).
555     */
556    for (p=f=fname; *p; p++) {
557       if (IsPathSeparator(*p)) {
558          f = p;                       /* set pos of last slash */
559       }
560    }
561    if (IsPathSeparator(*f)) {                   /* did we find a slash? */
562       f++;                            /* yes, point to filename */
563    } else {                           /* no, whole thing must be path name */
564       f = p;
565    }
566
567    /* If filename doesn't exist (i.e. root directory), we
568     * simply create a blank name consisting of a single
569     * space. This makes handling zero length filenames
570     * easier.
571     */
572    mdb->fnl = p - f;
573    if (mdb->fnl > 0) {
574       mdb->fname = check_pool_memory_size(mdb->fname, mdb->fnl+1);
575       memcpy(mdb->fname, f, mdb->fnl);    /* copy filename */
576       mdb->fname[mdb->fnl] = 0;
577    } else {
578       mdb->fname[0] = 0;
579       mdb->fnl = 0;
580    }
581
582    mdb->pnl = f - fname;
583    if (mdb->pnl > 0) {
584       mdb->path = check_pool_memory_size(mdb->path, mdb->pnl+1);
585       memcpy(mdb->path, fname, mdb->pnl);
586       mdb->path[mdb->pnl] = 0;
587    } else {
588       Mmsg1(&mdb->errmsg, _("Path length is zero. File=%s\n"), fname);
589       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
590       mdb->path[0] = 0;
591       mdb->pnl = 0;
592    }
593
594    Dmsg2(500, "split path=%s file=%s\n", mdb->path, mdb->fname);
595 }
596
597 /*
598  * List dashes as part of header for listing SQL results in a table
599  */
600 void
601 list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
602 {
603    SQL_FIELD  *field;
604    int i, j;
605
606    sql_field_seek(mdb, 0);
607    send(ctx, "+");
608    for (i = 0; i < sql_num_fields(mdb); i++) {
609       field = sql_fetch_field(mdb);
610       if (!field) {
611          break;
612       }
613       for (j = 0; j < (int)field->max_length + 2; j++) {
614          send(ctx, "-");
615       }
616       send(ctx, "+");
617    }
618    send(ctx, "\n");
619 }
620
621 /*
622  * If full_list is set, we list vertically, otherwise, we
623  * list on one line horizontally.
624  */
625 void
626 list_result(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type)
627 {
628    SQL_FIELD *field;
629    SQL_ROW row;
630    int i, col_len, max_len = 0;
631    char buf[2000], ewc[30];
632
633    Dmsg0(800, "list_result starts\n");
634    if (mdb->result == NULL || sql_num_rows(mdb) == 0) {
635       send(ctx, _("No results to list.\n"));
636       return;
637    }
638
639    Dmsg1(800, "list_result starts looking at %d fields\n", sql_num_fields(mdb));
640    /* determine column display widths */
641    sql_field_seek(mdb, 0);
642    for (i = 0; i < sql_num_fields(mdb); i++) {
643       Dmsg1(800, "list_result processing field %d\n", i);
644       field = sql_fetch_field(mdb);
645       if (!field) {
646          break;
647       }
648       col_len = cstrlen(field->name);
649       if (type == VERT_LIST) {
650          if (col_len > max_len) {
651             max_len = col_len;
652          }
653       } else {
654          if (IS_NUM(field->type) && (int)field->max_length > 0) { /* fixup for commas */
655             field->max_length += (field->max_length - 1) / 3;
656          }
657          if (col_len < (int)field->max_length) {
658             col_len = field->max_length;
659          }
660          if (col_len < 4 && !IS_NOT_NULL(field->flags)) {
661             col_len = 4;                 /* 4 = length of the word "NULL" */
662          }
663          field->max_length = col_len;    /* reset column info */
664       }
665    }
666
667    Dmsg0(800, "list_result finished first loop\n");
668    if (type == VERT_LIST) {
669       goto vertical_list;
670    }
671
672    Dmsg1(800, "list_result starts second loop looking at %d fields\n", sql_num_fields(mdb));
673    list_dashes(mdb, send, ctx);
674    send(ctx, "|");
675    sql_field_seek(mdb, 0);
676    for (i = 0; i < sql_num_fields(mdb); i++) {
677       Dmsg1(800, "list_result looking at field %d\n", i);
678       field = sql_fetch_field(mdb);
679       if (!field) {
680          break;
681       }
682       bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, field->name);
683       send(ctx, buf);
684    }
685    send(ctx, "\n");
686    list_dashes(mdb, send, ctx);
687
688    Dmsg1(800, "list_result starts third loop looking at %d fields\n", sql_num_fields(mdb));
689    while ((row = sql_fetch_row(mdb)) != NULL) {
690       sql_field_seek(mdb, 0);
691       send(ctx, "|");
692       for (i = 0; i < sql_num_fields(mdb); i++) {
693          field = sql_fetch_field(mdb);
694          if (!field) {
695             break;
696          }
697          if (row[i] == NULL) {
698             bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, "NULL");
699          } else if (IS_NUM(field->type) && !jcr->gui && is_an_integer(row[i])) {
700             bsnprintf(buf, sizeof(buf), " %*s |", (int)field->max_length,
701                       add_commas(row[i], ewc));
702          } else {
703             bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, row[i]);
704          }
705          send(ctx, buf);
706       }
707       send(ctx, "\n");
708    }
709    list_dashes(mdb, send, ctx);
710    return;
711
712 vertical_list:
713
714    Dmsg1(800, "list_result starts vertical list at %d fields\n", sql_num_fields(mdb));
715    while ((row = sql_fetch_row(mdb)) != NULL) {
716       sql_field_seek(mdb, 0);
717       for (i = 0; i < sql_num_fields(mdb); i++) {
718          field = sql_fetch_field(mdb);
719          if (!field) {
720             break;
721          }
722          if (row[i] == NULL) {
723             bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL");
724          } else if (IS_NUM(field->type) && !jcr->gui && is_an_integer(row[i])) {
725             bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name,
726                 add_commas(row[i], ewc));
727          } else {
728             bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]);
729          }
730          send(ctx, buf);
731       }
732       send(ctx, "\n");
733    }
734    return;
735 }
736
737 /* 
738  * Open a new connexion to mdb catalog. This function is used
739  * by batch and accurate mode.
740  */
741 bool db_open_batch_connexion(JCR *jcr, B_DB *mdb)
742 {
743    int multi_db=false;
744
745 #ifdef HAVE_BATCH_FILE_INSERT
746    multi_db=true;               /* we force a new connexion only if batch insert is enabled */
747 #endif
748
749    if (!jcr->db_batch) {
750       jcr->db_batch = db_init_database(jcr, 
751                                       mdb->db_name, 
752                                       mdb->db_user,
753                                       mdb->db_password, 
754                                       mdb->db_address,
755                                       mdb->db_port,
756                                       mdb->db_socket,
757                                       multi_db /* multi_db = true when using batch mode */);
758       if (!jcr->db_batch) {
759          Jmsg0(jcr, M_FATAL, 0, "Could not init batch connexion");
760          return false;
761       }
762
763       if (!db_open_database(jcr, jcr->db_batch)) {
764          Mmsg2(&jcr->db_batch->errmsg,  _("Could not open database \"%s\": ERR=%s\n"),
765               jcr->db_batch->db_name, db_strerror(jcr->db_batch));
766          Jmsg1(jcr, M_FATAL, 0, "%s", jcr->db_batch->errmsg);
767          return false;
768       }      
769       Dmsg3(100, "initdb ref=%d connected=%d db=%p\n", jcr->db_batch->ref_count,
770             jcr->db_batch->connected, jcr->db_batch->db);
771
772    }
773    return true;
774 }
775
776 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/