2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Bacula Catalog Database interface routines
22 * Almost generic set of SQL database interface routines
23 * (with a little more work)
24 * SQL engine specific routines are in mysql.c, postgresql.c,
27 * Written by Kern Sibbald, March 2000
29 * Note: at one point, this file was changed to class based by a certain
30 * programmer, and other than "wrapping" in a class, which is a trivial
31 * change for a C++ programmer, nothing substantial was done, yet all the
32 * code was recommitted under this programmer's name. Consequently, we
33 * undo those changes here.
38 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
42 /* Forward referenced subroutines */
43 void print_dashes(BDB *mdb);
44 void print_result(BDB *mdb);
46 dbid_list::dbid_list()
48 memset(this, 0, sizeof(dbid_list));
50 DBId = (DBId_t *)malloc(max_ids * sizeof(DBId_t));
51 num_ids = num_seen = tot_ids = 0;
55 dbid_list::~dbid_list()
61 * Called here to retrieve an string list from the database
63 int db_string_list_handler(void *ctx, int num_fields, char **row)
65 alist **val = (alist **)ctx;
68 (*val)->append(bstrdup(row[0]));
75 * Called here to retrieve an integer from the database
77 int db_int_handler(void *ctx, int num_fields, char **row)
79 uint32_t *val = (uint32_t *)ctx;
81 Dmsg1(800, "int_handler starts with row pointing at %x\n", row);
84 Dmsg1(800, "int_handler finds '%s'\n", row[0]);
85 *val = str_to_int64(row[0]);
87 Dmsg0(800, "int_handler finds zero\n");
90 Dmsg0(800, "int_handler finishes\n");
95 * Called here to retrieve a 32/64 bit integer from the database.
96 * The returned integer will be extended to 64 bit.
98 int db_int64_handler(void *ctx, int num_fields, char **row)
100 db_int64_ctx *lctx = (db_int64_ctx *)ctx;
103 lctx->value = str_to_int64(row[0]);
110 * Called here to retrieve a btime from the database.
111 * The returned integer will be extended to 64 bit.
113 int db_strtime_handler(void *ctx, int num_fields, char **row)
115 db_int64_ctx *lctx = (db_int64_ctx *)ctx;
118 lctx->value = str_to_utime(row[0]);
125 * Use to build a comma separated list of values from a query. "10,20,30"
127 int db_list_handler(void *ctx, int num_fields, char **row)
129 db_list_ctx *lctx = (db_list_ctx *)ctx;
130 if (num_fields == 1 && row[0]) {
137 * specific context passed from bdb_check_max_connections to
138 * db_max_connections_handler.
140 struct max_connections_context {
142 uint32_t nr_connections;
146 * Called here to retrieve max_connections from db
148 static int db_max_connections_handler(void *ctx, int num_fields, char **row)
150 struct max_connections_context *context;
153 context = (struct max_connections_context *)ctx;
154 switch (context->db->bdb_get_type_index()) {
162 context->nr_connections = str_to_int64(row[index]);
164 Dmsg0(800, "int_handler finds zero\n");
165 context->nr_connections = 0;
171 * Check catalog max_connections setting
173 bool BDB::bdb_check_max_connections(JCR *jcr, uint32_t max_concurrent_jobs)
175 struct max_connections_context context;
177 /* Without Batch insert, no need to verify max_connections */
178 if (!batch_insert_available())
182 context.nr_connections = 0;
184 /* Check max_connections setting */
185 if (!bdb_sql_query(sql_get_max_connections[bdb_get_type_index()],
186 db_max_connections_handler, &context)) {
187 Jmsg(jcr, M_ERROR, 0, "Can't verify max_connections settings %s", errmsg);
190 if (context.nr_connections && max_concurrent_jobs && max_concurrent_jobs > context.nr_connections) {
192 _("Potential performance problem:\n"
193 "max_connections=%d set for %s database \"%s\" should be larger than Director's "
194 "MaxConcurrentJobs=%d\n"),
195 context.nr_connections, bdb_get_engine_name(), get_db_name(), max_concurrent_jobs);
196 Jmsg(jcr, M_WARNING, 0, "%s", errmsg);
203 /* NOTE!!! The following routines expect that the
204 * calling subroutine sets and clears the mutex
207 /* Check that the tables correspond to the version we want */
208 bool BDB::bdb_check_version(JCR *jcr)
210 uint32_t bacula_db_version = 0;
211 const char *query = "SELECT VersionId FROM Version";
213 bacula_db_version = 0;
214 if (!bdb_sql_query(query, db_int_handler, (void *)&bacula_db_version)) {
215 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
218 if (bacula_db_version != BDB_VERSION) {
219 Mmsg(errmsg, "Version error for database \"%s\". Wanted %d, got %d\n",
220 get_db_name(), BDB_VERSION, bacula_db_version);
221 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
228 * Utility routine for queries. The database MUST be locked before calling here.
229 * Returns: 0 on failure
232 bool BDB::QueryDB(JCR *jcr, char *cmd, const char *file, int line)
235 if (!sql_query(cmd, QF_STORE_RESULT)) {
236 m_msg(file, line, &errmsg, _("query %s failed:\n%s\n"), cmd, sql_strerror());
237 if (use_fatal_jmsg()) {
238 j_msg(file, line, jcr, M_FATAL, 0, "%s", errmsg);
241 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
250 * Utility routine to do inserts
251 * Returns: 0 on failure
254 bool BDB::InsertDB(JCR *jcr, char *cmd, const char *file, int line)
256 if (!sql_query(cmd)) {
257 m_msg(file, line, &errmsg, _("insert %s failed:\n%s\n"), cmd, sql_strerror());
258 if (use_fatal_jmsg()) {
259 j_msg(file, line, jcr, M_FATAL, 0, "%s", errmsg);
262 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
266 int num_rows = sql_affected_rows();
269 m_msg(file, line, &errmsg, _("Insertion problem: affected_rows=%s\n"),
270 edit_uint64(num_rows, ed1));
272 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
280 /* Utility routine for updates.
281 * Returns: false on failure
284 * Some UPDATE queries must update record(s), other queries might not update
287 bool BDB::UpdateDB(JCR *jcr, char *cmd, bool can_be_empty,
288 const char *file, int line)
290 if (!sql_query(cmd)) {
291 m_msg(file, line, &errmsg, _("update %s failed:\n%s\n"), cmd, sql_strerror());
292 j_msg(file, line, jcr, M_ERROR, 0, "%s", errmsg);
294 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
298 int num_rows = sql_affected_rows();
299 if ((num_rows == 0 && !can_be_empty) || num_rows < 0) {
301 m_msg(file, line, &errmsg, _("Update failed: affected_rows=%s for %s\n"),
302 edit_uint64(num_rows, ed1), cmd);
304 // j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
312 /* Utility routine for deletes
314 * Returns: -1 on error
315 * n number of rows affected
317 int BDB::DeleteDB(JCR *jcr, char *cmd, const char *file, int line)
320 if (!sql_query(cmd)) {
321 m_msg(file, line, &errmsg, _("delete %s failed:\n%s\n"), cmd, sql_strerror());
322 j_msg(file, line, jcr, M_ERROR, 0, "%s", errmsg);
324 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
329 return sql_affected_rows();
334 * Get record max. Query is already in mdb->cmd
337 * Returns: -1 on failure
340 int get_sql_record_max(JCR *jcr, BDB *mdb)
345 if (mdb->QueryDB(jcr, mdb->cmd)) {
346 if ((row = mdb->sql_fetch_row()) == NULL) {
347 Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), mdb->sql_strerror());
350 stat = str_to_int64(row[0]);
352 mdb->sql_free_result();
354 Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), mdb->sql_strerror());
361 * Given a full filename, split it into its path
362 * and filename parts. They are returned in pool memory
363 * in the mdb structure.
365 void split_path_and_file(JCR *jcr, BDB *mdb, const char *afname)
369 /* Find path without the filename.
370 * I.e. everything after the last / is a "filename".
371 * OK, maybe it is a directory name, but we treat it like
372 * a filename. If we don't find a / then the whole name
373 * must be a path name (e.g. c:).
375 for (p=f=afname; *p; p++) {
376 if (IsPathSeparator(*p)) {
377 f = p; /* set pos of last slash */
380 if (IsPathSeparator(*f)) { /* did we find a slash? */
381 f++; /* yes, point to filename */
382 } else { /* no, whole thing must be path name */
386 /* If filename doesn't exist (i.e. root directory), we
387 * simply create a blank name consisting of a single
388 * space. This makes handling zero length filenames
393 mdb->fname = check_pool_memory_size(mdb->fname, mdb->fnl+1);
394 memcpy(mdb->fname, f, mdb->fnl); /* copy filename */
395 mdb->fname[mdb->fnl] = 0;
401 mdb->pnl = f - afname;
403 mdb->path = check_pool_memory_size(mdb->path, mdb->pnl+1);
404 memcpy(mdb->path, afname, mdb->pnl);
405 mdb->path[mdb->pnl] = 0;
407 Mmsg1(&mdb->errmsg, _("Path length is zero. File=%s\n"), afname);
408 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
413 Dmsg3(500, "split fname=%s: path=%s file=%s\n", afname, mdb->path, mdb->fname);
417 * Set maximum field length to something reasonable
419 static int max_length(int max_length)
421 int max_len = max_length;
425 } else if (max_len > 100) {
432 * List dashes as part of header for listing SQL results in a table
435 list_dashes(BDB *mdb, DB_LIST_HANDLER *send, void *ctx)
441 mdb->sql_field_seek(0);
443 for (i = 0; i < mdb->sql_num_fields(); i++) {
444 field = mdb->sql_fetch_field();
448 len = max_length(field->max_length + 2);
449 for (j = 0; j < len; j++) {
457 /* Small handler to print the last line of a list xxx command */
458 static void last_line_handler(void *vctx, const char *str)
460 LIST_CTX *ctx = (LIST_CTX *)vctx;
461 bstrncat(ctx->line, str, sizeof(ctx->line));
464 int list_result(void *vctx, int nb_col, char **row)
467 int i, col_len, max_len = 0;
468 char buf[2000], ewc[30];
470 LIST_CTX *pctx = (LIST_CTX *)vctx;
471 DB_LIST_HANDLER *send = pctx->send;
472 e_list_type type = pctx->type;
473 BDB *mdb = pctx->mdb;
474 void *ctx = pctx->ctx;
475 JCR *jcr = pctx->jcr;
480 Dmsg1(800, "list_result starts looking at %d fields\n", mdb->sql_num_fields());
481 /* determine column display widths */
482 mdb->sql_field_seek(0);
483 for (i = 0; i < mdb->sql_num_fields(); i++) {
484 Dmsg1(800, "list_result processing field %d\n", i);
485 field = mdb->sql_fetch_field();
489 col_len = cstrlen(field->name);
490 if (type == VERT_LIST) {
491 if (col_len > max_len) {
495 if (mdb->sql_field_is_numeric(field->type) && (int)field->max_length > 0) { /* fixup for commas */
496 field->max_length += (field->max_length - 1) / 3;
498 if (col_len < (int)field->max_length) {
499 col_len = field->max_length;
501 if (col_len < 4 && !mdb->sql_field_is_not_null(field->flags)) {
502 col_len = 4; /* 4 = length of the word "NULL" */
504 field->max_length = col_len; /* reset column info */
510 Dmsg0(800, "list_result finished first loop\n");
511 if (type == VERT_LIST) {
514 if (type == ARG_LIST) {
518 Dmsg1(800, "list_result starts second loop looking at %d fields\n",
519 mdb->sql_num_fields());
521 /* Keep the result to display the same line at the end of the table */
522 list_dashes(mdb, last_line_handler, pctx);
523 send(ctx, pctx->line);
526 mdb->sql_field_seek(0);
527 for (i = 0; i < mdb->sql_num_fields(); i++) {
528 Dmsg1(800, "list_result looking at field %d\n", i);
529 field = mdb->sql_fetch_field();
533 max_len = max_length(field->max_length);
534 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name);
538 list_dashes(mdb, send, ctx);
540 Dmsg1(800, "list_result starts third loop looking at %d fields\n",
541 mdb->sql_num_fields());
542 mdb->sql_field_seek(0);
544 for (i = 0; i < mdb->sql_num_fields(); i++) {
545 field = mdb->sql_fetch_field();
549 max_len = max_length(field->max_length);
550 if (row[i] == NULL) {
551 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL");
552 } else if (mdb->sql_field_is_numeric(field->type) && !jcr->gui && is_an_integer(row[i])) {
553 bsnprintf(buf, sizeof(buf), " %*s |", max_len,
554 add_commas(row[i], ewc));
556 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]);
565 Dmsg1(800, "list_result starts vertical list at %d fields\n", mdb->sql_num_fields());
566 mdb->sql_field_seek(0);
567 for (i = 0; i < mdb->sql_num_fields(); i++) {
568 field = mdb->sql_fetch_field();
572 if (row[i] == NULL) {
573 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL");
574 } else if (mdb->sql_field_is_numeric(field->type) && !jcr->gui && is_an_integer(row[i])) {
575 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name,
576 add_commas(row[i], ewc));
578 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]);
586 Dmsg1(800, "list_result starts simple list at %d fields\n", mdb->sql_num_fields());
587 mdb->sql_field_seek(0);
588 for (i = 0; i < mdb->sql_num_fields(); i++) {
589 field = mdb->sql_fetch_field();
593 if (row[i] == NULL) {
594 bsnprintf(buf, sizeof(buf), "%s%s=", (i>0?" ":""), field->name);
597 bsnprintf(buf, sizeof(buf), "%s%s=%s ", (i>0?" ":""), field->name, row[i]);
607 * If full_list is set, we list vertically, otherwise, we
608 * list on one line horizontally.
609 * Return number of rows
612 list_result(JCR *jcr, BDB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type)
616 int i, col_len, max_len = 0;
617 char buf[2000], ewc[30];
619 Dmsg0(800, "list_result starts\n");
620 if (mdb->sql_num_rows() == 0) {
621 send(ctx, _("No results to list.\n"));
622 return mdb->sql_num_rows();
625 Dmsg1(800, "list_result starts looking at %d fields\n", mdb->sql_num_fields());
626 /* determine column display widths */
627 mdb->sql_field_seek(0);
628 for (i = 0; i < mdb->sql_num_fields(); i++) {
629 Dmsg1(800, "list_result processing field %d\n", i);
630 field = mdb->sql_fetch_field();
634 col_len = cstrlen(field->name);
635 if (type == VERT_LIST) {
636 if (col_len > max_len) {
640 if (mdb->sql_field_is_numeric(field->type) && (int)field->max_length > 0) { /* fixup for commas */
641 field->max_length += (field->max_length - 1) / 3;
643 if (col_len < (int)field->max_length) {
644 col_len = field->max_length;
646 if (col_len < 4 && !mdb->sql_field_is_not_null(field->flags)) {
647 col_len = 4; /* 4 = length of the word "NULL" */
649 field->max_length = col_len; /* reset column info */
653 Dmsg0(800, "list_result finished first loop\n");
654 if (type == VERT_LIST) {
657 if (type == ARG_LIST) {
661 Dmsg1(800, "list_result starts second loop looking at %d fields\n", mdb->sql_num_fields());
662 list_dashes(mdb, send, ctx);
664 mdb->sql_field_seek(0);
665 for (i = 0; i < mdb->sql_num_fields(); i++) {
666 Dmsg1(800, "list_result looking at field %d\n", i);
667 field = mdb->sql_fetch_field();
671 max_len = max_length(field->max_length);
672 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name);
676 list_dashes(mdb, send, ctx);
678 Dmsg1(800, "list_result starts third loop looking at %d fields\n", mdb->sql_num_fields());
679 while ((row = mdb->sql_fetch_row()) != NULL) {
680 mdb->sql_field_seek(0);
682 for (i = 0; i < mdb->sql_num_fields(); i++) {
683 field = mdb->sql_fetch_field();
687 max_len = max_length(field->max_length);
688 if (row[i] == NULL) {
689 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL");
690 } else if (mdb->sql_field_is_numeric(field->type) && !jcr->gui && is_an_integer(row[i])) {
691 bsnprintf(buf, sizeof(buf), " %*s |", max_len,
692 add_commas(row[i], ewc));
694 strip_trailing_junk(row[i]);
695 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]);
701 list_dashes(mdb, send, ctx);
702 return mdb->sql_num_rows();
706 Dmsg1(800, "list_result starts vertical list at %d fields\n", mdb->sql_num_fields());
707 while ((row = mdb->sql_fetch_row()) != NULL) {
708 mdb->sql_field_seek(0);
709 for (i = 0; i < mdb->sql_num_fields(); i++) {
710 field = mdb->sql_fetch_field();
714 if (row[i] == NULL) {
715 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL");
716 } else if (mdb->sql_field_is_numeric(field->type) && !jcr->gui && is_an_integer(row[i])) {
717 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name,
718 add_commas(row[i], ewc));
720 strip_trailing_junk(row[i]);
721 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]);
730 Dmsg1(800, "list_result starts arg list at %d fields\n", mdb->sql_num_fields());
731 while ((row = mdb->sql_fetch_row()) != NULL) {
732 mdb->sql_field_seek(0);
733 for (i = 0; i < mdb->sql_num_fields(); i++) {
734 field = mdb->sql_fetch_field();
738 if (row[i] == NULL) {
739 bsnprintf(buf, sizeof(buf), "%s%s=", (i>0?" ":""), field->name);
742 bsnprintf(buf, sizeof(buf), "%s%s=%s", (i>0?" ":""), field->name, row[i]);
748 return mdb->sql_num_rows();
752 * Open a new connexion to mdb catalog. This function is used
753 * by batch and accurate mode.
755 bool BDB::bdb_open_batch_connexion(JCR *jcr)
759 multi_db = batch_insert_available();
761 if (!jcr->db_batch) {
762 jcr->db_batch = bdb_clone_database_connection(jcr, multi_db);
763 if (!jcr->db_batch) {
764 Mmsg0(&errmsg, _("Could not init database batch connection\n"));
765 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
769 if (!jcr->db_batch->bdb_open_database(jcr)) {
770 Mmsg2(&errmsg, _("Could not open database \"%s\": ERR=%s\n"),
771 jcr->db_batch->get_db_name(), jcr->db_batch->bdb_strerror());
772 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
780 * !!! WARNING !!! Use this function only when bacula is stopped.
781 * ie, after a fatal signal and before exiting the program
782 * Print information about a BDB object.
784 void bdb_debug_print(JCR *jcr, FILE *fp)
792 fprintf(fp, "BDB=%p db_name=%s db_user=%s connected=%s\n",
793 mdb, NPRTB(mdb->get_db_name()), NPRTB(mdb->get_db_user()), mdb->is_connected() ? "true" : "false");
794 fprintf(fp, "\tcmd=\"%s\" changes=%i\n", NPRTB(mdb->cmd), mdb->changes);
795 mdb->print_lock_info(fp);
798 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */