]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql.c
8c1105d2c69f0e79d6d64bbfbca7e0ca3bad6db0
[bacula/bacula] / bacula / src / cats / sql.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 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 three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    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: sql.c 8034 2008-11-11 14:33:46Z ricozz $
39  */
40
41 #include "bacula.h"
42
43 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
44
45 #include "cats.h"
46 #include "bdb_priv.h"
47 #include "sql_glue.h"
48
49 /* Forward referenced subroutines */
50 void print_dashes(B_DB *mdb);
51 void print_result(B_DB *mdb);
52
53 dbid_list::dbid_list()
54 {
55    memset(this, 0, sizeof(dbid_list));
56    max_ids = 1000;
57    DBId = (DBId_t *)malloc(max_ids * sizeof(DBId_t));
58    num_ids = num_seen = tot_ids = 0;
59    PurgedFiles = NULL;
60 }
61
62 dbid_list::~dbid_list()
63 {
64    free(DBId);
65 }
66
67 /*
68  * Called here to retrieve an integer from the database
69  */
70 int db_int_handler(void *ctx, int num_fields, char **row)
71 {
72    uint32_t *val = (uint32_t *)ctx;
73
74    Dmsg1(800, "int_handler starts with row pointing at %x\n", row);
75
76    if (row[0]) {
77       Dmsg1(800, "int_handler finds '%s'\n", row[0]);
78       *val = str_to_int64(row[0]);
79    } else {
80       Dmsg0(800, "int_handler finds zero\n");
81       *val = 0;
82    }
83    Dmsg0(800, "int_handler finishes\n");
84    return 0;
85 }
86
87 /*
88  * Called here to retrieve a 32/64 bit integer from the database.
89  *   The returned integer will be extended to 64 bit.
90  */
91 int db_int64_handler(void *ctx, int num_fields, char **row)
92 {
93    db_int64_ctx *lctx = (db_int64_ctx *)ctx;
94
95    if (row[0]) {
96       lctx->value = str_to_int64(row[0]);
97       lctx->count++;
98    }
99    return 0;
100 }
101
102 /*
103  * Use to build a comma separated list of values from a query. "10,20,30"
104  */
105 int db_list_handler(void *ctx, int num_fields, char **row)
106 {
107    db_list_ctx *lctx = (db_list_ctx *)ctx;
108    if (num_fields == 1 && row[0]) {
109       if (lctx->list[0]) {
110          pm_strcat(lctx->list, ",");
111       }
112       pm_strcat(lctx->list, row[0]);
113       lctx->count++;
114    }
115    return 0;
116 }
117
118 /*
119  *  * specific context passed from db_check_max_connections to db_max_connections_handler.
120  *   */
121 struct max_connections_context {
122    B_DB *db;
123    uint32_t nr_connections;
124 };
125
126 /*
127  *  * Called here to retrieve an integer from the database
128  *   */
129 static int db_max_connections_handler(void *ctx, int num_fields, char **row)
130 {
131    struct max_connections_context *context;
132    uint32_t index;
133
134    context = (struct max_connections_context *)ctx;
135    switch (db_get_type_index(context->db)) {
136    case SQL_TYPE_MYSQL:
137       index = 1;
138    default:
139       index = 0;
140    }
141
142    if (row[index]) {
143       context->nr_connections = str_to_int64(row[index]);
144    } else {
145       Dmsg0(800, "int_handler finds zero\n");
146       context->nr_connections = 0;
147    }
148    return 0;
149 }
150
151 /*
152  *  * Check catalog max_connections setting
153  *   */
154 bool db_check_max_connections(JCR *jcr, B_DB *mdb, uint32_t max_concurrent_jobs)
155 {
156    struct max_connections_context context;
157
158    /* Without Batch insert, no need to verify max_connections */
159    if (!mdb->batch_insert_available())
160       return true;
161
162    context.db = mdb;
163    context.nr_connections = 0;
164
165    /* Check max_connections setting */
166    if (!db_sql_query(mdb, sql_get_max_connections[db_get_type_index(mdb)],
167                      db_max_connections_handler, &context)) {
168       Jmsg(jcr, M_ERROR, 0, "Can't verify max_connections settings %s", mdb->errmsg);
169       return false;
170    }
171    if (context.nr_connections && max_concurrent_jobs && max_concurrent_jobs > context.nr_connections) {
172       Mmsg(mdb->errmsg,
173            _("Potential performance problem:\n"
174              "max_connections=%d set for %s database \"%s\" should be larger than Director's "
175              "MaxConcurrentJobs=%d\n"),
176            context.nr_connections, db_get_type(mdb), mdb->get_db_name(), max_concurrent_jobs);
177       Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
178       return false;
179    }
180
181    return true;
182 }
183
184 /* NOTE!!! The following routines expect that the
185  *  calling subroutine sets and clears the mutex
186  */
187
188 /* Check that the tables correspond to the version we want */
189 bool check_tables_version(JCR *jcr, B_DB *mdb)
190 {
191    uint32_t bacula_db_version = 0;
192    const char *query = "SELECT VersionId FROM Version";
193
194    bacula_db_version = 0;
195    if (!db_sql_query(mdb, query, db_int_handler, (void *)&bacula_db_version)) {
196       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
197       return false;
198    }
199    if (bacula_db_version != BDB_VERSION) {
200       Mmsg(mdb->errmsg, "Version error for database \"%s\". Wanted %d, got %d\n",
201           mdb->get_db_name(), BDB_VERSION, bacula_db_version);
202       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
203       return false;
204    }
205    return true;
206 }
207
208 /*
209  * Utility routine for queries. The database MUST be locked before calling here.
210  * Returns: 0 on failure
211  *          1 on success
212  */
213 int
214 QueryDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
215 {
216    sql_free_result(mdb);
217    if (!sql_query(mdb, cmd, QF_STORE_RESULT)) {
218       m_msg(file, line, &mdb->errmsg, _("query %s failed:\n%s\n"), cmd, sql_strerror(mdb));
219       j_msg(file, line, jcr, M_FATAL, 0, "%s", mdb->errmsg);
220       if (verbose) {
221          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
222       }
223       return 0;
224    }
225
226    return 1;
227 }
228
229 /*
230  * Utility routine to do inserts
231  * Returns: 0 on failure
232  *          1 on success
233  */
234 int
235 InsertDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
236 {
237    int num_rows;
238
239    if (!sql_query(mdb, cmd)) {
240       m_msg(file, line, &mdb->errmsg,  _("insert %s failed:\n%s\n"), cmd, sql_strerror(mdb));
241       j_msg(file, line, jcr, M_FATAL, 0, "%s", mdb->errmsg);
242       if (verbose) {
243          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
244       }
245       return 0;
246    }
247    num_rows = sql_affected_rows(mdb);
248    if (num_rows != 1) {
249       char ed1[30];
250       m_msg(file, line, &mdb->errmsg, _("Insertion problem: affected_rows=%s\n"),
251          edit_uint64(num_rows, ed1));
252       if (verbose) {
253          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
254       }
255       return 0;
256    }
257    mdb->changes++;
258    return 1;
259 }
260
261 /* Utility routine for updates.
262  *  Returns: 0 on failure
263  *           1 on success
264  */
265 int
266 UpdateDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
267 {
268    int num_rows;
269
270    if (!sql_query(mdb, cmd)) {
271       m_msg(file, line, &mdb->errmsg, _("update %s failed:\n%s\n"), cmd, sql_strerror(mdb));
272       j_msg(file, line, jcr, M_ERROR, 0, "%s", mdb->errmsg);
273       if (verbose) {
274          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
275       }
276       return 0;
277    }
278    num_rows = sql_affected_rows(mdb);
279    if (num_rows < 1) {
280       char ed1[30];
281       m_msg(file, line, &mdb->errmsg, _("Update failed: affected_rows=%s for %s\n"),
282          edit_uint64(num_rows, ed1), cmd);
283       if (verbose) {
284 //       j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
285       }
286       return 0;
287    }
288    mdb->changes++;
289    return 1;
290 }
291
292 /* Utility routine for deletes
293  *
294  * Returns: -1 on error
295  *           n number of rows affected
296  */
297 int
298 DeleteDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
299 {
300
301    if (!sql_query(mdb, cmd)) {
302       m_msg(file, line, &mdb->errmsg, _("delete %s failed:\n%s\n"), cmd, sql_strerror(mdb));
303       j_msg(file, line, jcr, M_ERROR, 0, "%s", mdb->errmsg);
304       if (verbose) {
305          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
306       }
307       return -1;
308    }
309    mdb->changes++;
310    return sql_affected_rows(mdb);
311 }
312
313
314 /*
315  * Get record max. Query is already in mdb->cmd
316  *  No locking done
317  *
318  * Returns: -1 on failure
319  *          count on success
320  */
321 int get_sql_record_max(JCR *jcr, B_DB *mdb)
322 {
323    SQL_ROW row;
324    int stat = 0;
325
326    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
327       if ((row = sql_fetch_row(mdb)) == NULL) {
328          Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
329          stat = -1;
330       } else {
331          stat = str_to_int64(row[0]);
332       }
333       sql_free_result(mdb);
334    } else {
335       Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
336       stat = -1;
337    }
338    return stat;
339 }
340
341 /*
342  *  * Return pre-edited error message
343  *   */
344 char *db_strerror(B_DB *mdb)
345 {
346    return mdb->errmsg;
347 }
348
349 /*
350  * Given a full filename, split it into its path
351  *  and filename parts. They are returned in pool memory
352  *  in the mdb structure.
353  */
354 void split_path_and_file(JCR *jcr, B_DB *mdb, const char *fname)
355 {
356    const char *p, *f;
357
358    /* Find path without the filename.
359     * I.e. everything after the last / is a "filename".
360     * OK, maybe it is a directory name, but we treat it like
361     * a filename. If we don't find a / then the whole name
362     * must be a path name (e.g. c:).
363     */
364    for (p=f=fname; *p; p++) {
365       if (IsPathSeparator(*p)) {
366          f = p;                       /* set pos of last slash */
367       }
368    }
369    if (IsPathSeparator(*f)) {                   /* did we find a slash? */
370       f++;                            /* yes, point to filename */
371    } else {                           /* no, whole thing must be path name */
372       f = p;
373    }
374
375    /* If filename doesn't exist (i.e. root directory), we
376     * simply create a blank name consisting of a single
377     * space. This makes handling zero length filenames
378     * easier.
379     */
380    mdb->fnl = p - f;
381    if (mdb->fnl > 0) {
382       mdb->fname = check_pool_memory_size(mdb->fname, mdb->fnl+1);
383       memcpy(mdb->fname, f, mdb->fnl);    /* copy filename */
384       mdb->fname[mdb->fnl] = 0;
385    } else {
386       mdb->fname[0] = 0;
387       mdb->fnl = 0;
388    }
389
390    mdb->pnl = f - fname;
391    if (mdb->pnl > 0) {
392       mdb->path = check_pool_memory_size(mdb->path, mdb->pnl+1);
393       memcpy(mdb->path, fname, mdb->pnl);
394       mdb->path[mdb->pnl] = 0;
395    } else {
396       Mmsg1(&mdb->errmsg, _("Path length is zero. File=%s\n"), fname);
397       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
398       mdb->path[0] = 0;
399       mdb->pnl = 0;
400    }
401
402    Dmsg2(500, "split path=%s file=%s\n", mdb->path, mdb->fname);
403 }
404
405 /*
406  * Set maximum field length to something reasonable
407  */
408 static int max_length(int max_length)
409 {
410    int max_len = max_length;
411    /* Sanity check */
412    if (max_len < 0) {
413       max_len = 2;
414    } else if (max_len > 100) {
415       max_len = 100;
416    }
417    return max_len;
418 }
419
420 /*
421  * List dashes as part of header for listing SQL results in a table
422  */
423 void
424 list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
425 {
426    SQL_FIELD  *field;
427    int i, j;
428    int len;
429
430    sql_field_seek(mdb, 0);
431    send(ctx, "+");
432    for (i = 0; i < sql_num_fields(mdb); i++) {
433       field = sql_fetch_field(mdb);
434       if (!field) {
435          break;
436       }
437       len = max_length(field->max_length + 2);
438       for (j = 0; j < len; j++) {
439          send(ctx, "-");
440       }
441       send(ctx, "+");
442    }
443    send(ctx, "\n");
444 }
445
446 /* Small handler to print the last line of a list xxx command */
447 static void last_line_handler(void *vctx, const char *str)
448 {
449    LIST_CTX *ctx = (LIST_CTX *)vctx;
450    bstrncat(ctx->line, str, sizeof(ctx->line));
451 }
452
453 int list_result(void *vctx, int nb_col, char **row)
454 {
455    SQL_FIELD *field;
456    int i, col_len, max_len = 0;
457    char buf[2000], ewc[30];
458
459    LIST_CTX *pctx = (LIST_CTX *)vctx;
460    DB_LIST_HANDLER *send = pctx->send;
461    e_list_type type = pctx->type;
462    B_DB *mdb = pctx->mdb;
463    void *ctx = pctx->ctx;
464    JCR *jcr = pctx->jcr;
465
466    if (!pctx->once) {
467       pctx->once = true;
468
469       Dmsg1(800, "list_result starts looking at %d fields\n", sql_num_fields(mdb));
470       /* determine column display widths */
471       sql_field_seek(mdb, 0);
472       for (i = 0; i < sql_num_fields(mdb); i++) {
473          Dmsg1(800, "list_result processing field %d\n", i);
474          field = sql_fetch_field(mdb);
475          if (!field) {
476             break;
477          }
478          col_len = cstrlen(field->name);
479          if (type == VERT_LIST) {
480             if (col_len > max_len) {
481                max_len = col_len;
482             }
483          } else {
484             if (sql_field_is_numeric(mdb, field->type) && (int)field->max_length > 0) { /* fixup for commas */
485                field->max_length += (field->max_length - 1) / 3;
486             }  
487             if (col_len < (int)field->max_length) {
488                col_len = field->max_length;
489             }  
490             if (col_len < 4 && !sql_field_is_not_null(mdb, field->flags)) {
491                col_len = 4;                 /* 4 = length of the word "NULL" */
492             }
493             field->max_length = col_len;    /* reset column info */
494          }
495       }
496
497       pctx->num_rows++;
498
499       Dmsg0(800, "list_result finished first loop\n");
500       if (type == VERT_LIST) {
501          goto vertical_list;
502       }
503
504       Dmsg1(800, "list_result starts second loop looking at %d fields\n", 
505             sql_num_fields(mdb));
506
507       /* Keep the result to display the same line at the end of the table */
508       list_dashes(mdb, last_line_handler, pctx);
509       send(ctx, pctx->line);
510
511       send(ctx, "|");
512       sql_field_seek(mdb, 0);
513       for (i = 0; i < sql_num_fields(mdb); i++) {
514          Dmsg1(800, "list_result looking at field %d\n", i);
515          field = sql_fetch_field(mdb);
516          if (!field) {
517             break;
518          }
519          max_len = max_length(field->max_length);
520          bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name);
521          send(ctx, buf);
522       }
523       send(ctx, "\n");
524       list_dashes(mdb, send, ctx);      
525    }
526    
527    Dmsg1(800, "list_result starts third loop looking at %d fields\n", 
528          sql_num_fields(mdb));
529
530    sql_field_seek(mdb, 0);
531    send(ctx, "|");
532    for (i = 0; i < sql_num_fields(mdb); i++) {
533       field = sql_fetch_field(mdb);
534       if (!field) {
535          break;
536       }
537       max_len = max_length(field->max_length);
538       if (row[i] == NULL) {
539          bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL");
540       } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) {
541          bsnprintf(buf, sizeof(buf), " %*s |", max_len,
542                    add_commas(row[i], ewc));
543       } else {
544          bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]);
545       }
546       send(ctx, buf);
547    }
548    send(ctx, "\n");
549    return 0;
550
551 vertical_list:
552
553    Dmsg1(800, "list_result starts vertical list at %d fields\n", sql_num_fields(mdb));
554
555    sql_field_seek(mdb, 0);
556    for (i = 0; i < sql_num_fields(mdb); i++) {
557       field = sql_fetch_field(mdb);
558       if (!field) {
559          break;
560       }
561       if (row[i] == NULL) {
562          bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL");
563       } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) {
564          bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name,
565                    add_commas(row[i], ewc));
566       } else {
567          bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]);
568       }
569       send(ctx, buf);
570    }
571    send(ctx, "\n");
572    return 0;
573 }
574
575 /* 
576  * Open a new connexion to mdb catalog. This function is used
577  * by batch and accurate mode.
578  */
579 bool db_open_batch_connexion(JCR *jcr, B_DB *mdb)
580 {
581    bool multi_db;
582
583    if (mdb->batch_insert_available())
584       multi_db = true;   /* we force a new connection only if batch insert is enabled */
585    else
586       multi_db = false;
587
588    if (!jcr->db_batch) {
589       jcr->db_batch = db_clone_database_connection(mdb, jcr, multi_db);
590       if (!jcr->db_batch) {
591          Mmsg0(&mdb->errmsg, _("Could not init database batch connection"));
592          Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
593          return false;
594       }
595
596       if (!db_open_database(jcr, jcr->db_batch)) {
597          Mmsg2(&mdb->errmsg,  _("Could not open database \"%s\": ERR=%s\n"),
598               jcr->db_batch->get_db_name(), db_strerror(jcr->db_batch));
599          Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
600          return false;
601       }      
602    }
603    return true;
604 }
605
606 /*
607  * !!! WARNING !!! Use this function only when bacula is stopped.
608  * ie, after a fatal signal and before exiting the program
609  * Print information about a B_DB object.
610  */
611 void db_debug_print(JCR *jcr, FILE *fp)
612 {
613    B_DB *mdb = jcr->db;
614
615    if (!mdb) {
616       return;
617    }
618
619    fprintf(fp, "B_DB=%p db_name=%s db_user=%s connected=%s\n",
620            mdb, NPRTB(mdb->get_db_name()), NPRTB(mdb->get_db_user()), mdb->is_connected() ? "true" : "false");
621    fprintf(fp, "\tcmd=\"%s\" changes=%i\n", NPRTB(mdb->cmd), mdb->changes);
622    mdb->print_lock_info(fp);
623 }
624
625 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */