]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql.c
ebl move Errors count up to be more easy to parse with Bweb
[bacula/bacula] / bacula / src / cats / sql.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 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 John Walker.
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  *
34  *    Kern Sibbald, March 2000
35  *
36  *    Version $Id$
37  */
38
39 /* The following is necessary so that we do not include
40  * the dummy external definition of B_DB.
41  */
42 #define __SQL_C                       /* indicate that this is sql.c */
43
44 #include "bacula.h"
45 #include "cats.h"
46
47 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL
48
49 uint32_t bacula_db_version = 0;
50
51 /* Forward referenced subroutines */
52 void print_dashes(B_DB *mdb);
53 void print_result(B_DB *mdb);
54
55 dbid_list::dbid_list() 
56 {
57    memset(this, 0, sizeof(dbid_list));
58    max_ids = 1000;
59    DBId = (DBId_t *)malloc(max_ids * sizeof(DBId_t));
60    num_ids = num_seen = tot_ids = 0;
61    PurgedFiles = NULL;
62 }
63
64 dbid_list::~dbid_list() 
65
66    free(DBId);
67 }
68
69
70 /*
71  * Called here to retrieve an integer from the database
72  */
73 static int int_handler(void *ctx, int num_fields, char **row)
74 {
75    uint32_t *val = (uint32_t *)ctx;
76
77    Dmsg1(800, "int_handler starts with row pointing at %x\n", row);
78
79    if (row[0]) {
80       Dmsg1(800, "int_handler finds '%s'\n", row[0]);
81       *val = str_to_int64(row[0]);
82    } else {
83       Dmsg0(800, "int_handler finds zero\n");
84       *val = 0;
85    }
86    Dmsg0(800, "int_handler finishes\n");
87    return 0;
88 }
89
90 /*
91  * Called here to retrieve a 32/64 bit integer from the database.
92  *   The returned integer will be extended to 64 bit.
93  */
94 int db_int64_handler(void *ctx, int num_fields, char **row)
95 {
96    db_int64_ctx *lctx = (db_int64_ctx *)ctx;
97
98    if (row[0]) {
99       lctx->value = str_to_int64(row[0]);
100       lctx->count++;
101    }
102    return 0;
103 }
104
105
106
107 /* NOTE!!! The following routines expect that the
108  *  calling subroutine sets and clears the mutex
109  */
110
111 /* Check that the tables correspond to the version we want */
112 bool check_tables_version(JCR *jcr, B_DB *mdb)
113 {
114    const char *query = "SELECT VersionId FROM Version";
115
116    bacula_db_version = 0;
117    if (!db_sql_query(mdb, query, int_handler, (void *)&bacula_db_version)) {
118       Mmsg(mdb->errmsg, "Database not created or server not running.\n");
119       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
120       return false;
121    }
122    if (bacula_db_version != BDB_VERSION) {
123       Mmsg(mdb->errmsg, "Version error for database \"%s\". Wanted %d, got %d\n",
124           mdb->db_name, BDB_VERSION, bacula_db_version);
125       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
126       return false;
127    }
128    return true;
129 }
130
131 /* Utility routine for queries. The database MUST be locked before calling here. */
132 int
133 QueryDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
134 {
135    int status;
136
137    sql_free_result(mdb);
138    if ((status=sql_query(mdb, cmd)) != 0) {
139       m_msg(file, line, &mdb->errmsg, _("query %s failed:\n%s\n"), cmd, sql_strerror(mdb));
140       j_msg(file, line, jcr, M_FATAL, 0, "%s", mdb->errmsg);
141       if (verbose) {
142          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
143       }
144       return 0;
145    }
146
147    mdb->result = sql_store_result(mdb);
148
149    return mdb->result != NULL;
150 }
151
152 /*
153  * Utility routine to do inserts
154  * Returns: 0 on failure
155  *          1 on success
156  */
157 int
158 InsertDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
159 {
160    if (sql_query(mdb, cmd)) {
161       m_msg(file, line, &mdb->errmsg,  _("insert %s failed:\n%s\n"), cmd, sql_strerror(mdb));
162       j_msg(file, line, jcr, M_FATAL, 0, "%s", mdb->errmsg);
163       if (verbose) {
164          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
165       }
166       return 0;
167    }
168    if (mdb->have_insert_id) {
169       mdb->num_rows = sql_affected_rows(mdb);
170    } else {
171       mdb->num_rows = 1;
172    }
173    if (mdb->num_rows != 1) {
174       char ed1[30];
175       m_msg(file, line, &mdb->errmsg, _("Insertion problem: affected_rows=%s\n"),
176          edit_uint64(mdb->num_rows, ed1));
177       if (verbose) {
178          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
179       }
180       return 0;
181    }
182    mdb->changes++;
183    return 1;
184 }
185
186 /* Utility routine for updates.
187  *  Returns: 0 on failure
188  *           1 on success
189  */
190 int
191 UpdateDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
192 {
193
194    if (sql_query(mdb, cmd)) {
195       m_msg(file, line, &mdb->errmsg, _("update %s failed:\n%s\n"), cmd, sql_strerror(mdb));
196       j_msg(file, line, jcr, M_ERROR, 0, "%s", mdb->errmsg);
197       if (verbose) {
198          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
199       }
200       return 0;
201    }
202    mdb->num_rows = sql_affected_rows(mdb);
203    if (mdb->num_rows < 1) {
204       char ed1[30];
205       m_msg(file, line, &mdb->errmsg, _("Update failed: affected_rows=%s for %s\n"),
206          edit_uint64(mdb->num_rows, ed1), cmd);
207       if (verbose) {
208 //       j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
209       }
210       return 0;
211    }
212    mdb->changes++;
213    return 1;
214 }
215
216 /* Utility routine for deletes
217  *
218  * Returns: -1 on error
219  *           n number of rows affected
220  */
221 int
222 DeleteDB(const char *file, int line, JCR *jcr, B_DB *mdb, char *cmd)
223 {
224
225    if (sql_query(mdb, cmd)) {
226       m_msg(file, line, &mdb->errmsg, _("delete %s failed:\n%s\n"), cmd, sql_strerror(mdb));
227       j_msg(file, line, jcr, M_ERROR, 0, "%s", mdb->errmsg);
228       if (verbose) {
229          j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
230       }
231       return -1;
232    }
233    mdb->changes++;
234    return sql_affected_rows(mdb);
235 }
236
237
238 /*
239  * Get record max. Query is already in mdb->cmd
240  *  No locking done
241  *
242  * Returns: -1 on failure
243  *          count on success
244  */
245 int get_sql_record_max(JCR *jcr, B_DB *mdb)
246 {
247    SQL_ROW row;
248    int stat = 0;
249
250    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
251       if ((row = sql_fetch_row(mdb)) == NULL) {
252          Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
253          stat = -1;
254       } else {
255          stat = str_to_int64(row[0]);
256       }
257       sql_free_result(mdb);
258    } else {
259       Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
260       stat = -1;
261    }
262    return stat;
263 }
264
265 /*
266  * Return pre-edited error message
267  */
268 char *db_strerror(B_DB *mdb)
269 {
270    return mdb->errmsg;
271 }
272
273 /*
274  * Lock database, this can be called multiple times by the same
275  *   thread without blocking, but must be unlocked the number of
276  *   times it was locked.
277  */
278 void _db_lock(const char *file, int line, B_DB *mdb)
279 {
280    int errstat;
281    if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
282       berrno be;
283       e_msg(file, line, M_FATAL, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
284            errstat, be.bstrerror(errstat));
285    }
286 }
287
288 /*
289  * Unlock the database. This can be called multiple times by the
290  *   same thread up to the number of times that thread called
291  *   db_lock()/
292  */
293 void _db_unlock(const char *file, int line, B_DB *mdb)
294 {
295    int errstat;
296    if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
297       berrno be;
298       e_msg(file, line, M_FATAL, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
299            errstat, be.bstrerror(errstat));
300    }
301 }
302
303 /*
304  * Start a transaction. This groups inserts and makes things
305  *  much more efficient. Usually started when inserting
306  *  file attributes.
307  */
308 void db_start_transaction(JCR *jcr, B_DB *mdb)
309 {
310    if (!jcr->attr) {
311       jcr->attr = get_pool_memory(PM_FNAME);
312    }
313    if (!jcr->ar) {
314       jcr->ar = (ATTR_DBR *)malloc(sizeof(ATTR_DBR));
315    }
316
317 #ifdef HAVE_SQLITE
318    if (!mdb->allow_transactions) {
319       return;
320    }
321    db_lock(mdb);
322    /* Allow only 10,000 changes per transaction */
323    if (mdb->transaction && mdb->changes > 10000) {
324       db_end_transaction(jcr, mdb);
325    }
326    if (!mdb->transaction) {
327       my_sqlite_query(mdb, "BEGIN");  /* begin transaction */
328       Dmsg0(400, "Start SQLite transaction\n");
329       mdb->transaction = 1;
330    }
331    db_unlock(mdb);
332 #endif
333
334 /*
335  * This is turned off because transactions break
336  * if multiple simultaneous jobs are run.
337  */
338 #ifdef HAVE_POSTGRESQL
339    if (!mdb->allow_transactions) {
340       return;
341    }
342    db_lock(mdb);
343    /* Allow only 25,000 changes per transaction */
344    if (mdb->transaction && mdb->changes > 25000) {
345       db_end_transaction(jcr, mdb);
346    }
347    if (!mdb->transaction) {
348       db_sql_query(mdb, "BEGIN", NULL, NULL);  /* begin transaction */
349       Dmsg0(400, "Start PosgreSQL transaction\n");
350       mdb->transaction = 1;
351    }
352    db_unlock(mdb);
353 #endif
354 }
355
356 void db_end_transaction(JCR *jcr, B_DB *mdb)
357 {
358    /*
359     * This can be called during thread cleanup and
360     *   the db may already be closed.  So simply return.
361     */
362    if (!mdb) {
363       return;
364    }
365
366    if (jcr && jcr->cached_attribute) {
367       Dmsg0(400, "Flush last cached attribute.\n");
368       if (!db_create_file_attributes_record(jcr, mdb, jcr->ar)) {
369          Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db));
370       }
371       jcr->cached_attribute = false;
372    }
373
374 #ifdef HAVE_SQLITE
375    if (!mdb->allow_transactions) {
376       return;
377    }
378    db_lock(mdb);
379    if (mdb->transaction) {
380       my_sqlite_query(mdb, "COMMIT"); /* end transaction */
381       mdb->transaction = 0;
382       Dmsg1(400, "End SQLite transaction changes=%d\n", mdb->changes);
383    }
384    mdb->changes = 0;
385    db_unlock(mdb);
386 #endif
387
388 #ifdef HAVE_POSTGRESQL
389    if (!mdb->allow_transactions) {
390       return;
391    }
392    db_lock(mdb);
393    if (mdb->transaction) {
394       db_sql_query(mdb, "COMMIT", NULL, NULL); /* end transaction */
395       mdb->transaction = 0;
396       Dmsg1(400, "End PostgreSQL transaction changes=%d\n", mdb->changes);
397    }
398    mdb->changes = 0;
399    db_unlock(mdb);
400 #endif
401 }
402
403 /*
404  * Given a full filename, split it into its path
405  *  and filename parts. They are returned in pool memory
406  *  in the mdb structure.
407  */
408 void split_path_and_file(JCR *jcr, B_DB *mdb, const char *fname)
409 {
410    const char *p, *f;
411
412    /* Find path without the filename.
413     * I.e. everything after the last / is a "filename".
414     * OK, maybe it is a directory name, but we treat it like
415     * a filename. If we don't find a / then the whole name
416     * must be a path name (e.g. c:).
417     */
418    for (p=f=fname; *p; p++) {
419       if (IsPathSeparator(*p)) {
420          f = p;                       /* set pos of last slash */
421       }
422    }
423    if (IsPathSeparator(*f)) {                   /* did we find a slash? */
424       f++;                            /* yes, point to filename */
425    } else {                           /* no, whole thing must be path name */
426       f = p;
427    }
428
429    /* If filename doesn't exist (i.e. root directory), we
430     * simply create a blank name consisting of a single
431     * space. This makes handling zero length filenames
432     * easier.
433     */
434    mdb->fnl = p - f;
435    if (mdb->fnl > 0) {
436       mdb->fname = check_pool_memory_size(mdb->fname, mdb->fnl+1);
437       memcpy(mdb->fname, f, mdb->fnl);    /* copy filename */
438       mdb->fname[mdb->fnl] = 0;
439    } else {
440       mdb->fname[0] = 0;
441       mdb->fnl = 0;
442    }
443
444    mdb->pnl = f - fname;
445    if (mdb->pnl > 0) {
446       mdb->path = check_pool_memory_size(mdb->path, mdb->pnl+1);
447       memcpy(mdb->path, fname, mdb->pnl);
448       mdb->path[mdb->pnl] = 0;
449    } else {
450       Mmsg1(&mdb->errmsg, _("Path length is zero. File=%s\n"), fname);
451       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
452       mdb->path[0] = 0;
453       mdb->pnl = 0;
454    }
455
456    Dmsg2(500, "split path=%s file=%s\n", mdb->path, mdb->fname);
457 }
458
459 /*
460  * List dashes as part of header for listing SQL results in a table
461  */
462 void
463 list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
464 {
465    SQL_FIELD  *field;
466    int i, j;
467
468    sql_field_seek(mdb, 0);
469    send(ctx, "+");
470    for (i = 0; i < sql_num_fields(mdb); i++) {
471       field = sql_fetch_field(mdb);
472       for (j = 0; j < (int)field->max_length + 2; j++) {
473          send(ctx, "-");
474       }
475       send(ctx, "+");
476    }
477    send(ctx, "\n");
478 }
479
480 /*
481  * If full_list is set, we list vertically, otherwise, we
482  * list on one line horizontally.
483  */
484 void
485 list_result(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type)
486 {
487    SQL_FIELD *field;
488    SQL_ROW row;
489    int i, col_len, max_len = 0;
490    char buf[2000], ewc[30];
491
492    Dmsg0(800, "list_result starts\n");
493    if (mdb->result == NULL || sql_num_rows(mdb) == 0) {
494       send(ctx, _("No results to list.\n"));
495       return;
496    }
497
498    Dmsg1(800, "list_result starts looking at %d fields\n", sql_num_fields(mdb));
499    /* determine column display widths */
500    sql_field_seek(mdb, 0);
501    for (i = 0; i < sql_num_fields(mdb); i++) {
502       Dmsg1(800, "list_result processing field %d\n", i);
503       field = sql_fetch_field(mdb);
504       col_len = cstrlen(field->name);
505       if (type == VERT_LIST) {
506          if (col_len > max_len) {
507             max_len = col_len;
508          }
509       } else {
510          if (IS_NUM(field->type) && (int)field->max_length > 0) { /* fixup for commas */
511             field->max_length += (field->max_length - 1) / 3;
512          }
513          if (col_len < (int)field->max_length) {
514             col_len = field->max_length;
515          }
516          if (col_len < 4 && !IS_NOT_NULL(field->flags)) {
517             col_len = 4;                 /* 4 = length of the word "NULL" */
518          }
519          field->max_length = col_len;    /* reset column info */
520       }
521    }
522
523    Dmsg0(800, "list_result finished first loop\n");
524    if (type == VERT_LIST) {
525       goto vertical_list;
526    }
527
528    Dmsg1(800, "list_result starts second loop looking at %d fields\n", sql_num_fields(mdb));
529    list_dashes(mdb, send, ctx);
530    send(ctx, "|");
531    sql_field_seek(mdb, 0);
532    for (i = 0; i < sql_num_fields(mdb); i++) {
533       Dmsg1(800, "list_result looking at field %d\n", i);
534       field = sql_fetch_field(mdb);
535       bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, field->name);
536       send(ctx, buf);
537    }
538    send(ctx, "\n");
539    list_dashes(mdb, send, ctx);
540
541    Dmsg1(800, "list_result starts third loop looking at %d fields\n", sql_num_fields(mdb));
542    while ((row = sql_fetch_row(mdb)) != NULL) {
543       sql_field_seek(mdb, 0);
544       send(ctx, "|");
545       for (i = 0; i < sql_num_fields(mdb); i++) {
546          field = sql_fetch_field(mdb);
547          if (row[i] == NULL) {
548             bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, "NULL");
549          } else if (IS_NUM(field->type) && !jcr->gui && is_an_integer(row[i])) {
550             bsnprintf(buf, sizeof(buf), " %*s |", (int)field->max_length,
551                       add_commas(row[i], ewc));
552          } else {
553             bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, row[i]);
554          }
555          send(ctx, buf);
556       }
557       send(ctx, "\n");
558    }
559    list_dashes(mdb, send, ctx);
560    return;
561
562 vertical_list:
563
564    Dmsg1(800, "list_result starts vertical list at %d fields\n", sql_num_fields(mdb));
565    while ((row = sql_fetch_row(mdb)) != NULL) {
566       sql_field_seek(mdb, 0);
567       for (i = 0; i < sql_num_fields(mdb); i++) {
568          field = sql_fetch_field(mdb);
569          if (row[i] == NULL) {
570             bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL");
571          } else if (IS_NUM(field->type) && !jcr->gui && is_an_integer(row[i])) {
572             bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name,
573                 add_commas(row[i], ewc));
574          } else {
575             bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]);
576          }
577          send(ctx, buf);
578       }
579       send(ctx, "\n");
580    }
581    return;
582 }
583
584
585 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/