2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
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.
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.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Bacula Catalog Database interface routines
23 * Almost generic set of SQL database interface routines
24 * (with a little more work)
25 * SQL engine specific routines are in mysql.c, postgresql.c,
28 * Written by Kern Sibbald, March 2000
30 * Note: at one point, this file was changed to class based by a certain
31 * programmer, and other than "wrapping" in a class, which is a trivial
32 * change for a C++ programmer, nothing substantial was done, yet all the
33 * code was recommitted under this programmer's name. Consequently, we
34 * undo those changes here.
39 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
43 /* Forward referenced subroutines */
44 void print_dashes(BDB *mdb);
45 void print_result(BDB *mdb);
47 dbid_list::dbid_list()
49 memset(this, 0, sizeof(dbid_list));
51 DBId = (DBId_t *)malloc(max_ids * sizeof(DBId_t));
52 num_ids = num_seen = tot_ids = 0;
56 dbid_list::~dbid_list()
62 * Called here to retrieve an string list from the database
64 int db_string_list_handler(void *ctx, int num_fields, char **row)
66 alist **val = (alist **)ctx;
69 (*val)->append(bstrdup(row[0]));
76 * Called here to retrieve an integer from the database
78 int db_int_handler(void *ctx, int num_fields, char **row)
80 uint32_t *val = (uint32_t *)ctx;
82 Dmsg1(800, "int_handler starts with row pointing at %x\n", row);
85 Dmsg1(800, "int_handler finds '%s'\n", row[0]);
86 *val = str_to_int64(row[0]);
88 Dmsg0(800, "int_handler finds zero\n");
91 Dmsg0(800, "int_handler finishes\n");
96 * Called here to retrieve a 32/64 bit integer from the database.
97 * The returned integer will be extended to 64 bit.
99 int db_int64_handler(void *ctx, int num_fields, char **row)
101 db_int64_ctx *lctx = (db_int64_ctx *)ctx;
104 lctx->value = str_to_int64(row[0]);
111 * Called here to retrieve a btime from the database.
112 * The returned integer will be extended to 64 bit.
114 int db_strtime_handler(void *ctx, int num_fields, char **row)
116 db_int64_ctx *lctx = (db_int64_ctx *)ctx;
119 lctx->value = str_to_utime(row[0]);
126 * Use to build a comma separated list of values from a query. "10,20,30"
128 int db_list_handler(void *ctx, int num_fields, char **row)
130 db_list_ctx *lctx = (db_list_ctx *)ctx;
131 if (num_fields == 1 && row[0]) {
138 * specific context passed from bdb_check_max_connections to
139 * db_max_connections_handler.
141 struct max_connections_context {
143 uint32_t nr_connections;
147 * Called here to retrieve max_connections from db
149 static int db_max_connections_handler(void *ctx, int num_fields, char **row)
151 struct max_connections_context *context;
154 context = (struct max_connections_context *)ctx;
155 switch (context->db->bdb_get_type_index()) {
163 context->nr_connections = str_to_int64(row[index]);
165 Dmsg0(800, "int_handler finds zero\n");
166 context->nr_connections = 0;
172 * Check catalog max_connections setting
174 bool BDB::bdb_check_max_connections(JCR *jcr, uint32_t max_concurrent_jobs)
176 struct max_connections_context context;
178 /* Without Batch insert, no need to verify max_connections */
179 if (!batch_insert_available())
183 context.nr_connections = 0;
185 /* Check max_connections setting */
186 if (!bdb_sql_query(sql_get_max_connections[bdb_get_type_index()],
187 db_max_connections_handler, &context)) {
188 Jmsg(jcr, M_ERROR, 0, "Can't verify max_connections settings %s", errmsg);
191 if (context.nr_connections && max_concurrent_jobs && max_concurrent_jobs > context.nr_connections) {
193 _("Potential performance problem:\n"
194 "max_connections=%d set for %s database \"%s\" should be larger than Director's "
195 "MaxConcurrentJobs=%d\n"),
196 context.nr_connections, bdb_get_engine_name(), get_db_name(), max_concurrent_jobs);
197 Jmsg(jcr, M_WARNING, 0, "%s", errmsg);
204 /* NOTE!!! The following routines expect that the
205 * calling subroutine sets and clears the mutex
208 /* Check that the tables correspond to the version we want */
209 bool BDB::bdb_check_version(JCR *jcr)
211 uint32_t bacula_db_version = 0;
212 const char *query = "SELECT VersionId FROM Version";
214 bacula_db_version = 0;
215 if (!bdb_sql_query(query, db_int_handler, (void *)&bacula_db_version)) {
216 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
219 if (bacula_db_version != BDB_VERSION) {
220 Mmsg(errmsg, "Version error for database \"%s\". Wanted %d, got %d\n",
221 get_db_name(), BDB_VERSION, bacula_db_version);
222 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
229 * Utility routine for queries. The database MUST be locked before calling here.
230 * Returns: 0 on failure
233 bool BDB::QueryDB(JCR *jcr, char *cmd, const char *file, int line)
236 if (!sql_query(cmd, QF_STORE_RESULT)) {
237 m_msg(file, line, &errmsg, _("query %s failed:\n%s\n"), cmd, sql_strerror());
238 if (use_fatal_jmsg()) {
239 j_msg(file, line, jcr, M_FATAL, 0, "%s", errmsg);
242 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
251 * Utility routine to do inserts
252 * Returns: 0 on failure
255 bool BDB::InsertDB(JCR *jcr, char *cmd, const char *file, int line)
257 if (!sql_query(cmd)) {
258 m_msg(file, line, &errmsg, _("insert %s failed:\n%s\n"), cmd, sql_strerror());
259 if (use_fatal_jmsg()) {
260 j_msg(file, line, jcr, M_FATAL, 0, "%s", errmsg);
263 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
267 int num_rows = sql_affected_rows();
270 m_msg(file, line, &errmsg, _("Insertion problem: affected_rows=%s\n"),
271 edit_uint64(num_rows, ed1));
273 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
281 /* Utility routine for updates.
282 * Returns: false on failure
285 bool BDB::UpdateDB(JCR *jcr, char *cmd, const char *file, int line)
287 if (!sql_query(cmd)) {
288 m_msg(file, line, &errmsg, _("update %s failed:\n%s\n"), cmd, sql_strerror());
289 j_msg(file, line, jcr, M_ERROR, 0, "%s", errmsg);
291 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
295 int num_rows = sql_affected_rows();
298 m_msg(file, line, &errmsg, _("Update failed: affected_rows=%s for %s\n"),
299 edit_uint64(num_rows, ed1), cmd);
301 // j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
309 /* Utility routine for deletes
311 * Returns: -1 on error
312 * n number of rows affected
314 int BDB::DeleteDB(JCR *jcr, char *cmd, const char *file, int line)
317 if (!sql_query(cmd)) {
318 m_msg(file, line, &errmsg, _("delete %s failed:\n%s\n"), cmd, sql_strerror());
319 j_msg(file, line, jcr, M_ERROR, 0, "%s", errmsg);
321 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
326 return sql_affected_rows();
331 * Get record max. Query is already in mdb->cmd
334 * Returns: -1 on failure
337 int get_sql_record_max(JCR *jcr, BDB *mdb)
342 if (mdb->QueryDB(jcr, mdb->cmd)) {
343 if ((row = mdb->sql_fetch_row()) == NULL) {
344 Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), mdb->sql_strerror());
347 stat = str_to_int64(row[0]);
349 mdb->sql_free_result();
351 Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), mdb->sql_strerror());
358 * Given a full filename, split it into its path
359 * and filename parts. They are returned in pool memory
360 * in the mdb structure.
362 void split_path_and_file(JCR *jcr, BDB *mdb, const char *afname)
366 /* Find path without the filename.
367 * I.e. everything after the last / is a "filename".
368 * OK, maybe it is a directory name, but we treat it like
369 * a filename. If we don't find a / then the whole name
370 * must be a path name (e.g. c:).
372 for (p=f=afname; *p; p++) {
373 if (IsPathSeparator(*p)) {
374 f = p; /* set pos of last slash */
377 if (IsPathSeparator(*f)) { /* did we find a slash? */
378 f++; /* yes, point to filename */
379 } else { /* no, whole thing must be path name */
383 /* If filename doesn't exist (i.e. root directory), we
384 * simply create a blank name consisting of a single
385 * space. This makes handling zero length filenames
390 mdb->fname = check_pool_memory_size(mdb->fname, mdb->fnl+1);
391 memcpy(mdb->fname, f, mdb->fnl); /* copy filename */
392 mdb->fname[mdb->fnl] = 0;
398 mdb->pnl = f - afname;
400 mdb->path = check_pool_memory_size(mdb->path, mdb->pnl+1);
401 memcpy(mdb->path, afname, mdb->pnl);
402 mdb->path[mdb->pnl] = 0;
404 Mmsg1(&mdb->errmsg, _("Path length is zero. File=%s\n"), afname);
405 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
410 Dmsg3(500, "split fname=%s: path=%s file=%s\n", afname, mdb->path, mdb->fname);
414 * Set maximum field length to something reasonable
416 static int max_length(int max_length)
418 int max_len = max_length;
422 } else if (max_len > 100) {
429 * List dashes as part of header for listing SQL results in a table
432 list_dashes(BDB *mdb, DB_LIST_HANDLER *send, void *ctx)
438 mdb->sql_field_seek(0);
440 for (i = 0; i < mdb->sql_num_fields(); i++) {
441 field = mdb->sql_fetch_field();
445 len = max_length(field->max_length + 2);
446 for (j = 0; j < len; j++) {
454 /* Small handler to print the last line of a list xxx command */
455 static void last_line_handler(void *vctx, const char *str)
457 LIST_CTX *ctx = (LIST_CTX *)vctx;
458 bstrncat(ctx->line, str, sizeof(ctx->line));
461 int list_result(void *vctx, int nb_col, char **row)
464 int i, col_len, max_len = 0;
465 char buf[2000], ewc[30];
467 LIST_CTX *pctx = (LIST_CTX *)vctx;
468 DB_LIST_HANDLER *send = pctx->send;
469 e_list_type type = pctx->type;
470 BDB *mdb = pctx->mdb;
471 void *ctx = pctx->ctx;
472 JCR *jcr = pctx->jcr;
477 Dmsg1(800, "list_result starts looking at %d fields\n", mdb->sql_num_fields());
478 /* determine column display widths */
479 mdb->sql_field_seek(0);
480 for (i = 0; i < mdb->sql_num_fields(); i++) {
481 Dmsg1(800, "list_result processing field %d\n", i);
482 field = mdb->sql_fetch_field();
486 col_len = cstrlen(field->name);
487 if (type == VERT_LIST) {
488 if (col_len > max_len) {
492 if (mdb->sql_field_is_numeric(field->type) && (int)field->max_length > 0) { /* fixup for commas */
493 field->max_length += (field->max_length - 1) / 3;
495 if (col_len < (int)field->max_length) {
496 col_len = field->max_length;
498 if (col_len < 4 && !mdb->sql_field_is_not_null(field->flags)) {
499 col_len = 4; /* 4 = length of the word "NULL" */
501 field->max_length = col_len; /* reset column info */
507 Dmsg0(800, "list_result finished first loop\n");
508 if (type == VERT_LIST) {
511 if (type == ARG_LIST) {
515 Dmsg1(800, "list_result starts second loop looking at %d fields\n",
516 mdb->sql_num_fields());
518 /* Keep the result to display the same line at the end of the table */
519 list_dashes(mdb, last_line_handler, pctx);
520 send(ctx, pctx->line);
523 mdb->sql_field_seek(0);
524 for (i = 0; i < mdb->sql_num_fields(); i++) {
525 Dmsg1(800, "list_result looking at field %d\n", i);
526 field = mdb->sql_fetch_field();
530 max_len = max_length(field->max_length);
531 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name);
535 list_dashes(mdb, send, ctx);
537 Dmsg1(800, "list_result starts third loop looking at %d fields\n",
538 mdb->sql_num_fields());
539 mdb->sql_field_seek(0);
541 for (i = 0; i < mdb->sql_num_fields(); i++) {
542 field = mdb->sql_fetch_field();
546 max_len = max_length(field->max_length);
547 if (row[i] == NULL) {
548 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL");
549 } else if (mdb->sql_field_is_numeric(field->type) && !jcr->gui && is_an_integer(row[i])) {
550 bsnprintf(buf, sizeof(buf), " %*s |", max_len,
551 add_commas(row[i], ewc));
553 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]);
562 Dmsg1(800, "list_result starts vertical list at %d fields\n", mdb->sql_num_fields());
563 mdb->sql_field_seek(0);
564 for (i = 0; i < mdb->sql_num_fields(); i++) {
565 field = mdb->sql_fetch_field();
569 if (row[i] == NULL) {
570 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL");
571 } else if (mdb->sql_field_is_numeric(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));
575 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]);
583 Dmsg1(800, "list_result starts simple list at %d fields\n", mdb->sql_num_fields());
584 mdb->sql_field_seek(0);
585 for (i = 0; i < mdb->sql_num_fields(); i++) {
586 field = mdb->sql_fetch_field();
590 if (row[i] == NULL) {
591 bsnprintf(buf, sizeof(buf), "%s%s=", (i>0?" ":""), field->name);
594 bsnprintf(buf, sizeof(buf), "%s%s=%s ", (i>0?" ":""), field->name, row[i]);
604 * If full_list is set, we list vertically, otherwise, we
605 * list on one line horizontally.
606 * Return number of rows
609 list_result(JCR *jcr, BDB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type)
613 int i, col_len, max_len = 0;
614 char buf[2000], ewc[30];
616 Dmsg0(800, "list_result starts\n");
617 if (mdb->sql_num_rows() == 0) {
618 send(ctx, _("No results to list.\n"));
619 return mdb->sql_num_rows();
622 Dmsg1(800, "list_result starts looking at %d fields\n", mdb->sql_num_fields());
623 /* determine column display widths */
624 mdb->sql_field_seek(0);
625 for (i = 0; i < mdb->sql_num_fields(); i++) {
626 Dmsg1(800, "list_result processing field %d\n", i);
627 field = mdb->sql_fetch_field();
631 col_len = cstrlen(field->name);
632 if (type == VERT_LIST) {
633 if (col_len > max_len) {
637 if (mdb->sql_field_is_numeric(field->type) && (int)field->max_length > 0) { /* fixup for commas */
638 field->max_length += (field->max_length - 1) / 3;
640 if (col_len < (int)field->max_length) {
641 col_len = field->max_length;
643 if (col_len < 4 && !mdb->sql_field_is_not_null(field->flags)) {
644 col_len = 4; /* 4 = length of the word "NULL" */
646 field->max_length = col_len; /* reset column info */
650 Dmsg0(800, "list_result finished first loop\n");
651 if (type == VERT_LIST) {
654 if (type == ARG_LIST) {
658 Dmsg1(800, "list_result starts second loop looking at %d fields\n", mdb->sql_num_fields());
659 list_dashes(mdb, send, ctx);
661 mdb->sql_field_seek(0);
662 for (i = 0; i < mdb->sql_num_fields(); i++) {
663 Dmsg1(800, "list_result looking at field %d\n", i);
664 field = mdb->sql_fetch_field();
668 max_len = max_length(field->max_length);
669 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name);
673 list_dashes(mdb, send, ctx);
675 Dmsg1(800, "list_result starts third loop looking at %d fields\n", mdb->sql_num_fields());
676 while ((row = mdb->sql_fetch_row()) != NULL) {
677 mdb->sql_field_seek(0);
679 for (i = 0; i < mdb->sql_num_fields(); i++) {
680 field = mdb->sql_fetch_field();
684 max_len = max_length(field->max_length);
685 if (row[i] == NULL) {
686 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL");
687 } else if (mdb->sql_field_is_numeric(field->type) && !jcr->gui && is_an_integer(row[i])) {
688 bsnprintf(buf, sizeof(buf), " %*s |", max_len,
689 add_commas(row[i], ewc));
691 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]);
697 list_dashes(mdb, send, ctx);
698 return mdb->sql_num_rows();
702 Dmsg1(800, "list_result starts vertical list at %d fields\n", mdb->sql_num_fields());
703 while ((row = mdb->sql_fetch_row()) != NULL) {
704 mdb->sql_field_seek(0);
705 for (i = 0; i < mdb->sql_num_fields(); i++) {
706 field = mdb->sql_fetch_field();
710 if (row[i] == NULL) {
711 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL");
712 } else if (mdb->sql_field_is_numeric(field->type) && !jcr->gui && is_an_integer(row[i])) {
713 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name,
714 add_commas(row[i], ewc));
716 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]);
725 Dmsg1(800, "list_result starts arg list at %d fields\n", mdb->sql_num_fields());
726 while ((row = mdb->sql_fetch_row()) != NULL) {
727 mdb->sql_field_seek(0);
728 for (i = 0; i < mdb->sql_num_fields(); i++) {
729 field = mdb->sql_fetch_field();
733 if (row[i] == NULL) {
734 bsnprintf(buf, sizeof(buf), "%s%s=", (i>0?" ":""), field->name);
737 bsnprintf(buf, sizeof(buf), "%s%s=%s", (i>0?" ":""), field->name, row[i]);
743 return mdb->sql_num_rows();
747 * Open a new connexion to mdb catalog. This function is used
748 * by batch and accurate mode.
750 bool BDB::bdb_open_batch_connexion(JCR *jcr)
754 multi_db = batch_insert_available();
756 if (!jcr->db_batch) {
757 jcr->db_batch = bdb_clone_database_connection(jcr, multi_db);
758 if (!jcr->db_batch) {
759 Mmsg0(&errmsg, _("Could not init database batch connection\n"));
760 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
764 if (!jcr->db_batch->bdb_open_database(jcr)) {
765 Mmsg2(&errmsg, _("Could not open database \"%s\": ERR=%s\n"),
766 jcr->db_batch->get_db_name(), jcr->db_batch->bdb_strerror());
767 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
775 * !!! WARNING !!! Use this function only when bacula is stopped.
776 * ie, after a fatal signal and before exiting the program
777 * Print information about a BDB object.
779 void bdb_debug_print(JCR *jcr, FILE *fp)
787 fprintf(fp, "BDB=%p db_name=%s db_user=%s connected=%s\n",
788 mdb, NPRTB(mdb->get_db_name()), NPRTB(mdb->get_db_user()), mdb->is_connected() ? "true" : "false");
789 fprintf(fp, "\tcmd=\"%s\" changes=%i\n", NPRTB(mdb->cmd), mdb->changes);
790 mdb->print_lock_info(fp);
793 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */