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 bool BDB::UpdateDB(JCR *jcr, char *cmd, const char *file, int line)
286 if (!sql_query(cmd)) {
287 m_msg(file, line, &errmsg, _("update %s failed:\n%s\n"), cmd, sql_strerror());
288 j_msg(file, line, jcr, M_ERROR, 0, "%s", errmsg);
290 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
294 int num_rows = sql_affected_rows();
297 m_msg(file, line, &errmsg, _("Update failed: affected_rows=%s for %s\n"),
298 edit_uint64(num_rows, ed1), cmd);
300 // j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
308 /* Utility routine for deletes
310 * Returns: -1 on error
311 * n number of rows affected
313 int BDB::DeleteDB(JCR *jcr, char *cmd, const char *file, int line)
316 if (!sql_query(cmd)) {
317 m_msg(file, line, &errmsg, _("delete %s failed:\n%s\n"), cmd, sql_strerror());
318 j_msg(file, line, jcr, M_ERROR, 0, "%s", errmsg);
320 j_msg(file, line, jcr, M_INFO, 0, "%s\n", cmd);
325 return sql_affected_rows();
330 * Get record max. Query is already in mdb->cmd
333 * Returns: -1 on failure
336 int get_sql_record_max(JCR *jcr, BDB *mdb)
341 if (mdb->QueryDB(jcr, mdb->cmd)) {
342 if ((row = mdb->sql_fetch_row()) == NULL) {
343 Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), mdb->sql_strerror());
346 stat = str_to_int64(row[0]);
348 mdb->sql_free_result();
350 Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), mdb->sql_strerror());
357 * Given a full filename, split it into its path
358 * and filename parts. They are returned in pool memory
359 * in the mdb structure.
361 void split_path_and_file(JCR *jcr, BDB *mdb, const char *afname)
365 /* Find path without the filename.
366 * I.e. everything after the last / is a "filename".
367 * OK, maybe it is a directory name, but we treat it like
368 * a filename. If we don't find a / then the whole name
369 * must be a path name (e.g. c:).
371 for (p=f=afname; *p; p++) {
372 if (IsPathSeparator(*p)) {
373 f = p; /* set pos of last slash */
376 if (IsPathSeparator(*f)) { /* did we find a slash? */
377 f++; /* yes, point to filename */
378 } else { /* no, whole thing must be path name */
382 /* If filename doesn't exist (i.e. root directory), we
383 * simply create a blank name consisting of a single
384 * space. This makes handling zero length filenames
389 mdb->fname = check_pool_memory_size(mdb->fname, mdb->fnl+1);
390 memcpy(mdb->fname, f, mdb->fnl); /* copy filename */
391 mdb->fname[mdb->fnl] = 0;
397 mdb->pnl = f - afname;
399 mdb->path = check_pool_memory_size(mdb->path, mdb->pnl+1);
400 memcpy(mdb->path, afname, mdb->pnl);
401 mdb->path[mdb->pnl] = 0;
403 Mmsg1(&mdb->errmsg, _("Path length is zero. File=%s\n"), afname);
404 Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
409 Dmsg3(500, "split fname=%s: path=%s file=%s\n", afname, mdb->path, mdb->fname);
413 * Set maximum field length to something reasonable
415 static int max_length(int max_length)
417 int max_len = max_length;
421 } else if (max_len > 100) {
428 * List dashes as part of header for listing SQL results in a table
431 list_dashes(BDB *mdb, DB_LIST_HANDLER *send, void *ctx)
437 mdb->sql_field_seek(0);
439 for (i = 0; i < mdb->sql_num_fields(); i++) {
440 field = mdb->sql_fetch_field();
444 len = max_length(field->max_length + 2);
445 for (j = 0; j < len; j++) {
453 /* Small handler to print the last line of a list xxx command */
454 static void last_line_handler(void *vctx, const char *str)
456 LIST_CTX *ctx = (LIST_CTX *)vctx;
457 bstrncat(ctx->line, str, sizeof(ctx->line));
460 int list_result(void *vctx, int nb_col, char **row)
463 int i, col_len, max_len = 0;
464 char buf[2000], ewc[30];
466 LIST_CTX *pctx = (LIST_CTX *)vctx;
467 DB_LIST_HANDLER *send = pctx->send;
468 e_list_type type = pctx->type;
469 BDB *mdb = pctx->mdb;
470 void *ctx = pctx->ctx;
471 JCR *jcr = pctx->jcr;
476 Dmsg1(800, "list_result starts looking at %d fields\n", mdb->sql_num_fields());
477 /* determine column display widths */
478 mdb->sql_field_seek(0);
479 for (i = 0; i < mdb->sql_num_fields(); i++) {
480 Dmsg1(800, "list_result processing field %d\n", i);
481 field = mdb->sql_fetch_field();
485 col_len = cstrlen(field->name);
486 if (type == VERT_LIST) {
487 if (col_len > max_len) {
491 if (mdb->sql_field_is_numeric(field->type) && (int)field->max_length > 0) { /* fixup for commas */
492 field->max_length += (field->max_length - 1) / 3;
494 if (col_len < (int)field->max_length) {
495 col_len = field->max_length;
497 if (col_len < 4 && !mdb->sql_field_is_not_null(field->flags)) {
498 col_len = 4; /* 4 = length of the word "NULL" */
500 field->max_length = col_len; /* reset column info */
506 Dmsg0(800, "list_result finished first loop\n");
507 if (type == VERT_LIST) {
510 if (type == ARG_LIST) {
514 Dmsg1(800, "list_result starts second loop looking at %d fields\n",
515 mdb->sql_num_fields());
517 /* Keep the result to display the same line at the end of the table */
518 list_dashes(mdb, last_line_handler, pctx);
519 send(ctx, pctx->line);
522 mdb->sql_field_seek(0);
523 for (i = 0; i < mdb->sql_num_fields(); i++) {
524 Dmsg1(800, "list_result looking at field %d\n", i);
525 field = mdb->sql_fetch_field();
529 max_len = max_length(field->max_length);
530 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name);
534 list_dashes(mdb, send, ctx);
536 Dmsg1(800, "list_result starts third loop looking at %d fields\n",
537 mdb->sql_num_fields());
538 mdb->sql_field_seek(0);
540 for (i = 0; i < mdb->sql_num_fields(); i++) {
541 field = mdb->sql_fetch_field();
545 max_len = max_length(field->max_length);
546 if (row[i] == NULL) {
547 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL");
548 } else if (mdb->sql_field_is_numeric(field->type) && !jcr->gui && is_an_integer(row[i])) {
549 bsnprintf(buf, sizeof(buf), " %*s |", max_len,
550 add_commas(row[i], ewc));
552 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]);
561 Dmsg1(800, "list_result starts vertical list at %d fields\n", mdb->sql_num_fields());
562 mdb->sql_field_seek(0);
563 for (i = 0; i < mdb->sql_num_fields(); i++) {
564 field = mdb->sql_fetch_field();
568 if (row[i] == NULL) {
569 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL");
570 } else if (mdb->sql_field_is_numeric(field->type) && !jcr->gui && is_an_integer(row[i])) {
571 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name,
572 add_commas(row[i], ewc));
574 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]);
582 Dmsg1(800, "list_result starts simple list at %d fields\n", mdb->sql_num_fields());
583 mdb->sql_field_seek(0);
584 for (i = 0; i < mdb->sql_num_fields(); i++) {
585 field = mdb->sql_fetch_field();
589 if (row[i] == NULL) {
590 bsnprintf(buf, sizeof(buf), "%s%s=", (i>0?" ":""), field->name);
593 bsnprintf(buf, sizeof(buf), "%s%s=%s ", (i>0?" ":""), field->name, row[i]);
603 * If full_list is set, we list vertically, otherwise, we
604 * list on one line horizontally.
605 * Return number of rows
608 list_result(JCR *jcr, BDB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type)
612 int i, col_len, max_len = 0;
613 char buf[2000], ewc[30];
615 Dmsg0(800, "list_result starts\n");
616 if (mdb->sql_num_rows() == 0) {
617 send(ctx, _("No results to list.\n"));
618 return mdb->sql_num_rows();
621 Dmsg1(800, "list_result starts looking at %d fields\n", mdb->sql_num_fields());
622 /* determine column display widths */
623 mdb->sql_field_seek(0);
624 for (i = 0; i < mdb->sql_num_fields(); i++) {
625 Dmsg1(800, "list_result processing field %d\n", i);
626 field = mdb->sql_fetch_field();
630 col_len = cstrlen(field->name);
631 if (type == VERT_LIST) {
632 if (col_len > max_len) {
636 if (mdb->sql_field_is_numeric(field->type) && (int)field->max_length > 0) { /* fixup for commas */
637 field->max_length += (field->max_length - 1) / 3;
639 if (col_len < (int)field->max_length) {
640 col_len = field->max_length;
642 if (col_len < 4 && !mdb->sql_field_is_not_null(field->flags)) {
643 col_len = 4; /* 4 = length of the word "NULL" */
645 field->max_length = col_len; /* reset column info */
649 Dmsg0(800, "list_result finished first loop\n");
650 if (type == VERT_LIST) {
653 if (type == ARG_LIST) {
657 Dmsg1(800, "list_result starts second loop looking at %d fields\n", mdb->sql_num_fields());
658 list_dashes(mdb, send, ctx);
660 mdb->sql_field_seek(0);
661 for (i = 0; i < mdb->sql_num_fields(); i++) {
662 Dmsg1(800, "list_result looking at field %d\n", i);
663 field = mdb->sql_fetch_field();
667 max_len = max_length(field->max_length);
668 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name);
672 list_dashes(mdb, send, ctx);
674 Dmsg1(800, "list_result starts third loop looking at %d fields\n", mdb->sql_num_fields());
675 while ((row = mdb->sql_fetch_row()) != NULL) {
676 mdb->sql_field_seek(0);
678 for (i = 0; i < mdb->sql_num_fields(); i++) {
679 field = mdb->sql_fetch_field();
683 max_len = max_length(field->max_length);
684 if (row[i] == NULL) {
685 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL");
686 } else if (mdb->sql_field_is_numeric(field->type) && !jcr->gui && is_an_integer(row[i])) {
687 bsnprintf(buf, sizeof(buf), " %*s |", max_len,
688 add_commas(row[i], ewc));
690 bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]);
696 list_dashes(mdb, send, ctx);
697 return mdb->sql_num_rows();
701 Dmsg1(800, "list_result starts vertical list at %d fields\n", mdb->sql_num_fields());
702 while ((row = mdb->sql_fetch_row()) != NULL) {
703 mdb->sql_field_seek(0);
704 for (i = 0; i < mdb->sql_num_fields(); i++) {
705 field = mdb->sql_fetch_field();
709 if (row[i] == NULL) {
710 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL");
711 } else if (mdb->sql_field_is_numeric(field->type) && !jcr->gui && is_an_integer(row[i])) {
712 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name,
713 add_commas(row[i], ewc));
715 bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]);
724 Dmsg1(800, "list_result starts arg list at %d fields\n", mdb->sql_num_fields());
725 while ((row = mdb->sql_fetch_row()) != NULL) {
726 mdb->sql_field_seek(0);
727 for (i = 0; i < mdb->sql_num_fields(); i++) {
728 field = mdb->sql_fetch_field();
732 if (row[i] == NULL) {
733 bsnprintf(buf, sizeof(buf), "%s%s=", (i>0?" ":""), field->name);
736 bsnprintf(buf, sizeof(buf), "%s%s=%s", (i>0?" ":""), field->name, row[i]);
742 return mdb->sql_num_rows();
746 * Open a new connexion to mdb catalog. This function is used
747 * by batch and accurate mode.
749 bool BDB::bdb_open_batch_connexion(JCR *jcr)
753 multi_db = batch_insert_available();
755 if (!jcr->db_batch) {
756 jcr->db_batch = bdb_clone_database_connection(jcr, multi_db);
757 if (!jcr->db_batch) {
758 Mmsg0(&errmsg, _("Could not init database batch connection\n"));
759 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
763 if (!jcr->db_batch->bdb_open_database(jcr)) {
764 Mmsg2(&errmsg, _("Could not open database \"%s\": ERR=%s\n"),
765 jcr->db_batch->get_db_name(), jcr->db_batch->bdb_strerror());
766 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
774 * !!! WARNING !!! Use this function only when bacula is stopped.
775 * ie, after a fatal signal and before exiting the program
776 * Print information about a BDB object.
778 void bdb_debug_print(JCR *jcr, FILE *fp)
786 fprintf(fp, "BDB=%p db_name=%s db_user=%s connected=%s\n",
787 mdb, NPRTB(mdb->get_db_name()), NPRTB(mdb->get_db_user()), mdb->is_connected() ? "true" : "false");
788 fprintf(fp, "\tcmd=\"%s\" changes=%i\n", NPRTB(mdb->cmd), mdb->changes);
789 mdb->print_lock_info(fp);
792 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */