From d89b8bea48e0469fb5fcd2656d017a514749464a Mon Sep 17 00:00:00 2001 From: Eric Bollengier Date: Fri, 28 Jan 2011 14:41:55 +0100 Subject: [PATCH] Implement db_big_sql_query() that uses cursor on PostgreSQL and limit memory usage in db_list_xxx By default on PostgreSQL, db_sql_query() stores the query results in memory, it can take lots of resources when dealing with job output, accurate or restore. This new mode uses cursors and fetches results 100 by 100. db_list_xxx functions doesn't store the entire query result anymore. Commands like "list joblog" or "list files" are now stable in memory usage. (for MySQL and PostgreSQL) --- bacula/src/cats/bdb_postgresql.h | 2 + bacula/src/cats/cats.h | 44 +++++++- bacula/src/cats/postgresql.c | 74 +++++++++++++ bacula/src/cats/protos.h | 1 + bacula/src/cats/sql.c | 183 ++++++++++++++++--------------- bacula/src/cats/sql_get.c | 2 +- bacula/src/cats/sql_glue.c | 5 + bacula/src/cats/sql_glue.h | 1 + bacula/src/cats/sql_list.c | 92 ++++++++++------ 9 files changed, 281 insertions(+), 123 deletions(-) diff --git a/bacula/src/cats/bdb_postgresql.h b/bacula/src/cats/bdb_postgresql.h index 10ccda1c06..ee57926efc 100644 --- a/bacula/src/cats/bdb_postgresql.h +++ b/bacula/src/cats/bdb_postgresql.h @@ -33,6 +33,7 @@ class B_DB_POSTGRESQL: public B_DB_PRIV { private: PGconn *m_db_handle; PGresult *m_result; + POOLMEM *m_buf; /* Buffer to manipulate queries */ public: B_DB_POSTGRESQL(JCR *jcr, const char *db_driver, const char *db_name, @@ -52,6 +53,7 @@ public: void db_start_transaction(JCR *jcr); void db_end_transaction(JCR *jcr); bool db_sql_query(const char *query, DB_RESULT_HANDLER *result_handler, void *ctx); + bool db_big_sql_query(const char *query, DB_RESULT_HANDLER *result_handler, void *ctx); void sql_free_result(void); SQL_ROW sql_fetch_row(void); bool sql_query(const char *query, int flags=0); diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index a41ea7ac55..d70540f6ea 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -490,6 +490,12 @@ public: virtual void db_start_transaction(JCR *jcr) = 0; virtual void db_end_transaction(JCR *jcr) = 0; virtual bool db_sql_query(const char *query, DB_RESULT_HANDLER *result_handler, void *ctx) = 0; + + /* By default, we use db_sql_query */ + virtual bool db_big_sql_query(const char *query, + DB_RESULT_HANDLER *result_handler, void *ctx) { + return db_sql_query(query, result_handler, ctx); + }; }; /* sql_query Query Flags */ @@ -505,10 +511,46 @@ public: #include "jcr.h" #include "sql_cmds.h" +/* Object used in db_list_xxx function */ +class LIST_CTX { +public: + char line[256]; /* Used to print last dash line */ + int32_t num_rows; + + e_list_type type; /* Vertical/Horizontal */ + DB_LIST_HANDLER *send; /* send data back */ + bool once; /* Used to print header one time */ + void *ctx; /* send() user argument */ + B_DB *mdb; + JCR *jcr; + + void empty() { + once = false; + line[0] = '\0'; + } + + void send_dashes() { + if (*line) { + send(ctx, line); + } + } + + LIST_CTX(JCR *j, B_DB *m, DB_LIST_HANDLER *h, void *c, e_list_type t) { + line[0] = '\0'; + once = false; + num_rows = 0; + type = t; + send = h; + ctx = c; + jcr = j; + mdb = m; + } +}; + /* * Some functions exported by sql.c for use within the cats directory. */ -void list_result(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type); +int list_result(void *vctx, int cols, char **row); void list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx); int get_sql_record_max(JCR *jcr, B_DB *mdb); bool check_tables_version(JCR *jcr, B_DB *mdb); diff --git a/bacula/src/cats/postgresql.c b/bacula/src/cats/postgresql.c index a4b2163667..1371aa5df9 100644 --- a/bacula/src/cats/postgresql.c +++ b/bacula/src/cats/postgresql.c @@ -118,6 +118,7 @@ B_DB_POSTGRESQL::B_DB_POSTGRESQL(JCR *jcr, path = get_pool_memory(PM_FNAME); esc_name = get_pool_memory(PM_FNAME); esc_path = get_pool_memory(PM_FNAME); + m_buf = get_pool_memory(PM_FNAME); m_allow_transactions = mult_db_connections; /* @@ -246,6 +247,7 @@ bool B_DB_POSTGRESQL::db_open_database(JCR *jcr) } sql_query("SET datestyle TO 'ISO, YMD'"); + sql_query("SET cursor_tuple_fraction=1"); /* * Tell PostgreSQL we are using standard conforming strings @@ -285,6 +287,7 @@ void B_DB_POSTGRESQL::db_close_database(JCR *jcr) free_pool_memory(path); free_pool_memory(esc_name); free_pool_memory(esc_path); + free_pool_memory(m_buf); if (m_db_driver) { free(m_db_driver); } @@ -455,6 +458,72 @@ void B_DB_POSTGRESQL::db_end_transaction(JCR *jcr) db_unlock(this); } + +/* + * Submit a general SQL command (cmd), and for each row returned, + * the result_handler is called with the ctx. + */ +bool B_DB_POSTGRESQL::db_big_sql_query(const char *query, + DB_RESULT_HANDLER *result_handler, + void *ctx) +{ + SQL_ROW row; + bool retval = false; + bool in_transaction = m_transaction; + + Dmsg1(500, "db_sql_query starts with '%s'\n", query); + + /* This code handles only SELECT queries */ + if (strncasecmp(query, "SELECT", 6) != 0) { + return db_sql_query(query, result_handler, ctx); + } + + db_lock(this); + + if (!result_handler) { /* no need of big_query without handler */ + goto bail_out; + } + + if (!in_transaction) { /* CURSOR needs transaction */ + sql_query("BEGIN"); + } + + Mmsg(m_buf, "DECLARE _bac_cursor CURSOR FOR %s", query); + + if (!sql_query(m_buf)) { + Mmsg(errmsg, _("Query failed: %s: ERR=%s\n"), m_buf, sql_strerror()); + Dmsg0(50, "db_sql_query failed\n"); + goto bail_out; + } + + do { + if (!sql_query("FETCH 100 FROM _bac_cursor")) { + goto bail_out; + } + while ((row = sql_fetch_row()) != NULL) { + Dmsg1(500, "Fetching %d rows\n", m_num_rows); + if (result_handler(ctx, m_num_fields, row)) + break; + } + PQclear(m_result); + m_result = NULL; + + } while (m_num_rows > 0); /* TODO: Can probably test against 100 */ + + sql_free_result(); + + if (!in_transaction) { + sql_query("COMMIT"); /* end transaction */ + } + + Dmsg0(500, "db_big_sql_query finished\n"); + retval = true; + +bail_out: + db_unlock(this); + return retval; +} + /* * Submit a general SQL command (cmd), and for each row returned, * the result_handler is called with the ctx. @@ -592,6 +661,11 @@ SQL_ROW B_DB_POSTGRESQL::sql_fetch_row(void) Dmsg0(500, "sql_fetch_row start\n"); + if (m_num_fields == 0) { /* No field, no row */ + Dmsg0(500, "sql_fetch_row finishes returning NULL, no fields\n"); + return NULL; + } + if (!m_rows || m_rows_size < m_num_fields) { if (m_rows) { Dmsg0(500, "sql_fetch_row freeing space\n"); diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index acb5ac4f07..0c824682bf 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -116,6 +116,7 @@ enum e_list_type { HORZ_LIST, VERT_LIST }; + void db_list_pool_records(JCR *jcr, B_DB *db, POOL_DBR *pr, DB_LIST_HANDLER sendit, void *ctx, e_list_type type); void db_list_job_records(JCR *jcr, B_DB *db, JOB_DBR *jr, DB_LIST_HANDLER sendit, void *ctx, e_list_type type); void db_list_job_totals(JCR *jcr, B_DB *db, JOB_DBR *jr, DB_LIST_HANDLER sendit, void *ctx); diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c index 4efc0e813d..8c1105d2c6 100644 --- a/bacula/src/cats/sql.c +++ b/bacula/src/cats/sql.c @@ -443,122 +443,133 @@ list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx) send(ctx, "\n"); } -/* - * If full_list is set, we list vertically, otherwise, we - * list on one line horizontally. - */ -void -list_result(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type) +/* Small handler to print the last line of a list xxx command */ +static void last_line_handler(void *vctx, const char *str) +{ + LIST_CTX *ctx = (LIST_CTX *)vctx; + bstrncat(ctx->line, str, sizeof(ctx->line)); +} + +int list_result(void *vctx, int nb_col, char **row) { SQL_FIELD *field; - SQL_ROW row; int i, col_len, max_len = 0; char buf[2000], ewc[30]; - Dmsg0(800, "list_result starts\n"); - if (sql_num_rows(mdb) == 0) { - send(ctx, _("No results to list.\n")); - return; - } + LIST_CTX *pctx = (LIST_CTX *)vctx; + DB_LIST_HANDLER *send = pctx->send; + e_list_type type = pctx->type; + B_DB *mdb = pctx->mdb; + void *ctx = pctx->ctx; + JCR *jcr = pctx->jcr; - Dmsg1(800, "list_result starts looking at %d fields\n", sql_num_fields(mdb)); - /* determine column display widths */ - sql_field_seek(mdb, 0); - for (i = 0; i < sql_num_fields(mdb); i++) { - Dmsg1(800, "list_result processing field %d\n", i); - field = sql_fetch_field(mdb); - if (!field) { - break; - } - col_len = cstrlen(field->name); - if (type == VERT_LIST) { - if (col_len > max_len) { - max_len = col_len; + if (!pctx->once) { + pctx->once = true; + + Dmsg1(800, "list_result starts looking at %d fields\n", sql_num_fields(mdb)); + /* determine column display widths */ + sql_field_seek(mdb, 0); + for (i = 0; i < sql_num_fields(mdb); i++) { + Dmsg1(800, "list_result processing field %d\n", i); + field = sql_fetch_field(mdb); + if (!field) { + break; } - } else { - if (sql_field_is_numeric(mdb, field->type) && (int)field->max_length > 0) { /* fixup for commas */ - field->max_length += (field->max_length - 1) / 3; - } - if (col_len < (int)field->max_length) { - col_len = field->max_length; - } - if (col_len < 4 && !sql_field_is_not_null(mdb, field->flags)) { - col_len = 4; /* 4 = length of the word "NULL" */ + col_len = cstrlen(field->name); + if (type == VERT_LIST) { + if (col_len > max_len) { + max_len = col_len; + } + } else { + if (sql_field_is_numeric(mdb, field->type) && (int)field->max_length > 0) { /* fixup for commas */ + field->max_length += (field->max_length - 1) / 3; + } + if (col_len < (int)field->max_length) { + col_len = field->max_length; + } + if (col_len < 4 && !sql_field_is_not_null(mdb, field->flags)) { + col_len = 4; /* 4 = length of the word "NULL" */ + } + field->max_length = col_len; /* reset column info */ } - field->max_length = col_len; /* reset column info */ } - } - Dmsg0(800, "list_result finished first loop\n"); - if (type == VERT_LIST) { - goto vertical_list; - } + pctx->num_rows++; - Dmsg1(800, "list_result starts second loop looking at %d fields\n", sql_num_fields(mdb)); - list_dashes(mdb, send, ctx); - send(ctx, "|"); - sql_field_seek(mdb, 0); - for (i = 0; i < sql_num_fields(mdb); i++) { - Dmsg1(800, "list_result looking at field %d\n", i); - field = sql_fetch_field(mdb); - if (!field) { - break; + Dmsg0(800, "list_result finished first loop\n"); + if (type == VERT_LIST) { + goto vertical_list; } - max_len = max_length(field->max_length); - bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name); - send(ctx, buf); - } - send(ctx, "\n"); - list_dashes(mdb, send, ctx); - Dmsg1(800, "list_result starts third loop looking at %d fields\n", sql_num_fields(mdb)); - while ((row = sql_fetch_row(mdb)) != NULL) { - sql_field_seek(mdb, 0); + Dmsg1(800, "list_result starts second loop looking at %d fields\n", + sql_num_fields(mdb)); + + /* Keep the result to display the same line at the end of the table */ + list_dashes(mdb, last_line_handler, pctx); + send(ctx, pctx->line); + send(ctx, "|"); + sql_field_seek(mdb, 0); for (i = 0; i < sql_num_fields(mdb); i++) { + Dmsg1(800, "list_result looking at field %d\n", i); field = sql_fetch_field(mdb); if (!field) { break; } max_len = max_length(field->max_length); - if (row[i] == NULL) { - bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL"); - } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { - bsnprintf(buf, sizeof(buf), " %*s |", max_len, - add_commas(row[i], ewc)); - } else { - bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]); - } + bsnprintf(buf, sizeof(buf), " %-*s |", max_len, field->name); send(ctx, buf); } send(ctx, "\n"); + list_dashes(mdb, send, ctx); + } + + Dmsg1(800, "list_result starts third loop looking at %d fields\n", + sql_num_fields(mdb)); + + sql_field_seek(mdb, 0); + send(ctx, "|"); + for (i = 0; i < sql_num_fields(mdb); i++) { + field = sql_fetch_field(mdb); + if (!field) { + break; + } + max_len = max_length(field->max_length); + if (row[i] == NULL) { + bsnprintf(buf, sizeof(buf), " %-*s |", max_len, "NULL"); + } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { + bsnprintf(buf, sizeof(buf), " %*s |", max_len, + add_commas(row[i], ewc)); + } else { + bsnprintf(buf, sizeof(buf), " %-*s |", max_len, row[i]); + } + send(ctx, buf); } - list_dashes(mdb, send, ctx); - return; + send(ctx, "\n"); + return 0; vertical_list: Dmsg1(800, "list_result starts vertical list at %d fields\n", sql_num_fields(mdb)); - while ((row = sql_fetch_row(mdb)) != NULL) { - sql_field_seek(mdb, 0); - for (i = 0; i < sql_num_fields(mdb); i++) { - field = sql_fetch_field(mdb); - if (!field) { - break; - } - if (row[i] == NULL) { - bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL"); - } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { - bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, - add_commas(row[i], ewc)); - } else { - bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]); - } - send(ctx, buf); + + sql_field_seek(mdb, 0); + for (i = 0; i < sql_num_fields(mdb); i++) { + field = sql_fetch_field(mdb); + if (!field) { + break; } - send(ctx, "\n"); + if (row[i] == NULL) { + bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL"); + } else if (sql_field_is_numeric(mdb, field->type) && !jcr->gui && is_an_integer(row[i])) { + bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, + add_commas(row[i], ewc)); + } else { + bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, row[i]); + } + send(ctx, buf); } - return; + send(ctx, "\n"); + return 0; } /* diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index 3d11c08048..7fee824ad7 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -1158,7 +1158,7 @@ bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids, Dmsg1(100, "q=%s\n", buf.c_str()); - return db_sql_query(mdb, buf.c_str(), result_handler, ctx); + return db_big_sql_query(mdb, buf.c_str(), result_handler, ctx); } /** diff --git a/bacula/src/cats/sql_glue.c b/bacula/src/cats/sql_glue.c index 2e4590be6d..a86195ce36 100644 --- a/bacula/src/cats/sql_glue.c +++ b/bacula/src/cats/sql_glue.c @@ -121,6 +121,11 @@ bool db_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handle return mdb->db_sql_query(query, result_handler, ctx); } +bool db_big_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handler, void *ctx) +{ + return mdb->db_big_sql_query(query, result_handler, ctx); +} + void sql_free_result(B_DB *mdb) { ((B_DB_PRIV *)mdb)->sql_free_result(); diff --git a/bacula/src/cats/sql_glue.h b/bacula/src/cats/sql_glue.h index 14e3945408..ecfad4f25c 100644 --- a/bacula/src/cats/sql_glue.h +++ b/bacula/src/cats/sql_glue.h @@ -53,6 +53,7 @@ void db_start_transaction(JCR *jcr, B_DB *mdb); void db_end_transaction(JCR *jcr, B_DB *mdb); bool db_sql_query(B_DB *mdb, const char *query, int flags=0); bool db_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handler, void *ctx); +bool db_big_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handler, void *ctx); #ifdef _BDB_PRIV_INTERFACE_ void sql_free_result(B_DB *mdb); diff --git a/bacula/src/cats/sql_list.c b/bacula/src/cats/sql_list.c index d3770872ba..05fb1c5cbc 100644 --- a/bacula/src/cats/sql_list.c +++ b/bacula/src/cats/sql_list.c @@ -55,8 +55,11 @@ int db_list_sql_query(JCR *jcr, B_DB *mdb, const char *query, DB_LIST_HANDLER *sendit, void *ctx, int verbose, e_list_type type) { + LIST_CTX lctx(jcr, mdb, sendit, ctx, type); + db_lock(mdb); - if (!sql_query(mdb, query, QF_STORE_RESULT)) { + + if (!db_big_sql_query(mdb, query, list_result, &lctx)) { Mmsg(mdb->errmsg, _("Query failed: %s\n"), sql_strerror(mdb)); if (verbose) { sendit(ctx, mdb->errmsg); @@ -65,7 +68,8 @@ int db_list_sql_query(JCR *jcr, B_DB *mdb, const char *query, DB_LIST_HANDLER *s return 0; } - list_result(jcr, mdb, sendit, ctx, type); + lctx.send_dashes(); + sql_free_result(mdb); db_unlock(mdb); return 1; @@ -75,6 +79,8 @@ void db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { + LIST_CTX lctx(jcr, mdb, sendit, ctx, type); + db_lock(mdb); if (type == VERT_LIST) { if (pdbr->Name[0] != 0) { @@ -100,12 +106,12 @@ db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr, } } - if (!QUERY_DB(jcr, mdb, mdb->cmd)) { + if (!db_big_sql_query(mdb, mdb->cmd, list_result, &lctx)) { db_unlock(mdb); return; } - list_result(jcr, mdb, sendit, ctx, type); + lctx.send_dashes(); sql_free_result(mdb); db_unlock(mdb); @@ -114,6 +120,8 @@ db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr, void db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { + LIST_CTX lctx(jcr, mdb, sendit, ctx, type); + db_lock(mdb); if (type == VERT_LIST) { Mmsg(mdb->cmd, "SELECT ClientId,Name,Uname,AutoPrune,FileRetention," @@ -124,12 +132,11 @@ db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, "FROM Client ORDER BY ClientId"); } - if (!QUERY_DB(jcr, mdb, mdb->cmd)) { + if (!db_big_sql_query(mdb, mdb->cmd, list_result, &lctx)) { db_unlock(mdb); return; } - - list_result(jcr, mdb, sendit, ctx, type); + lctx.send_dashes(); sql_free_result(mdb); db_unlock(mdb); @@ -145,6 +152,8 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { char ed1[50]; + LIST_CTX lctx(jcr, mdb, sendit, ctx, type); + db_lock(mdb); if (type == VERT_LIST) { if (mdbr->VolumeName[0] != 0) { @@ -182,12 +191,12 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, } } - if (!QUERY_DB(jcr, mdb, mdb->cmd)) { + if (!db_big_sql_query(mdb, mdb->cmd, list_result, &lctx)) { db_unlock(mdb); return; } - list_result(jcr, mdb, sendit, ctx, type); + lctx.send_dashes(); sql_free_result(mdb); db_unlock(mdb); @@ -197,6 +206,8 @@ void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { char ed1[50]; + LIST_CTX lctx(jcr, mdb, sendit, ctx, type); + db_lock(mdb); if (type == VERT_LIST) { if (JobId > 0) { /* do by JobId */ @@ -222,12 +233,13 @@ void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId, "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId"); } } - if (!QUERY_DB(jcr, mdb, mdb->cmd)) { + + if (!db_big_sql_query(mdb, mdb->cmd, list_result, &lctx)) { db_unlock(mdb); return; } - list_result(jcr, mdb, sendit, ctx, type); + lctx.send_dashes(); sql_free_result(mdb); db_unlock(mdb); @@ -237,6 +249,7 @@ void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId, void db_list_copies_records(JCR *jcr, B_DB *mdb, uint32_t limit, char *JobIds, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { + LIST_CTX lctx(jcr, mdb, sendit, ctx, type); POOL_MEM str_limit(PM_MESSAGE); POOL_MEM str_jobids(PM_MESSAGE); @@ -259,20 +272,18 @@ void db_list_copies_records(JCR *jcr, B_DB *mdb, uint32_t limit, char *JobIds, "WHERE Job.Type = '%c' %s ORDER BY Job.PriorJobId DESC %s", (char) JT_JOB_COPY, str_jobids.c_str(), str_limit.c_str()); - if (!QUERY_DB(jcr, mdb, mdb->cmd)) { - goto bail_out; + if (JobIds && JobIds[0]) { + sendit(ctx, _("These JobIds have copies as follows:\n")); + } else { + sendit(ctx, _("The catalog contains copies as follows:\n")); } - if (sql_num_rows(mdb)) { - if (JobIds && JobIds[0]) { - sendit(ctx, _("These JobIds have copies as follows:\n")); - } else { - sendit(ctx, _("The catalog contains copies as follows:\n")); - } - - list_result(jcr, mdb, sendit, ctx, type); + if (!db_big_sql_query(mdb, mdb->cmd, list_result, &lctx)) { + goto bail_out; } + lctx.send_dashes(); + sql_free_result(mdb); bail_out: @@ -283,6 +294,7 @@ void db_list_joblog_records(JCR *jcr, B_DB *mdb, uint32_t JobId, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { char ed1[50]; + LIST_CTX lctx(jcr, mdb, sendit, ctx, type); if (JobId <= 0) { return; @@ -295,11 +307,12 @@ void db_list_joblog_records(JCR *jcr, B_DB *mdb, uint32_t JobId, Mmsg(mdb->cmd, "SELECT LogText FROM Log " "WHERE Log.JobId=%s", edit_int64(JobId, ed1)); } - if (!QUERY_DB(jcr, mdb, mdb->cmd)) { + + if (!db_big_sql_query(mdb, mdb->cmd, list_result, &lctx)) { goto bail_out; } - list_result(jcr, mdb, sendit, ctx, type); + lctx.send_dashes(); sql_free_result(mdb); @@ -320,6 +333,8 @@ db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, { char ed1[50]; char limit[100]; + LIST_CTX lctx(jcr, mdb, sendit, ctx, type); + db_lock(mdb); if (jr->limit > 0) { snprintf(limit, sizeof(limit), " LIMIT %d", jr->limit); @@ -370,11 +385,12 @@ db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, "FROM Job ORDER BY StartTime,JobId ASC%s", limit); } } - if (!QUERY_DB(jcr, mdb, mdb->cmd)) { + + if (!db_big_sql_query(mdb, mdb->cmd, list_result, &lctx)) { db_unlock(mdb); return; } - list_result(jcr, mdb, sendit, ctx, type); + lctx.send_dashes(); sql_free_result(mdb); db_unlock(mdb); @@ -387,18 +403,19 @@ db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void db_list_job_totals(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx) { + LIST_CTX lctx(jcr, mdb, sendit, ctx, HORZ_LIST); + db_lock(mdb); /* List by Job */ Mmsg(mdb->cmd, "SELECT count(*) AS Jobs,sum(JobFiles) " "AS Files,sum(JobBytes) AS Bytes,Name AS Job FROM Job GROUP BY Name"); - if (!QUERY_DB(jcr, mdb, mdb->cmd)) { + if (!db_sql_query(mdb, mdb->cmd, list_result, &lctx)) { db_unlock(mdb); return; } - - list_result(jcr, mdb, sendit, ctx, HORZ_LIST); + lctx.send_dashes(); sql_free_result(mdb); @@ -406,12 +423,13 @@ db_list_job_totals(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, vo Mmsg(mdb->cmd, "SELECT count(*) AS Jobs,sum(JobFiles) " "AS Files,sum(JobBytes) As Bytes FROM Job"); - if (!QUERY_DB(jcr, mdb, mdb->cmd)) { + lctx.empty(); + if (!db_sql_query(mdb, mdb->cmd, list_result, &lctx)) { db_unlock(mdb); return; } - list_result(jcr, mdb, sendit, ctx, HORZ_LIST); + lctx.send_dashes(); sql_free_result(mdb); db_unlock(mdb); @@ -420,7 +438,9 @@ db_list_job_totals(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, vo void db_list_files_for_job(JCR *jcr, B_DB *mdb, JobId_t jobid, DB_LIST_HANDLER *sendit, void *ctx) { + LIST_CTX lctx(jcr, mdb, sendit, ctx, HORZ_LIST); char ed1[50]; + db_lock(mdb); /* @@ -452,12 +472,12 @@ db_list_files_for_job(JCR *jcr, B_DB *mdb, JobId_t jobid, DB_LIST_HANDLER *sendi edit_int64(jobid, ed1), ed1); } - if (!QUERY_DB(jcr, mdb, mdb->cmd)) { + if (!db_big_sql_query(mdb, mdb->cmd, list_result, &lctx)) { db_unlock(mdb); return; } - - list_result(jcr, mdb, sendit, ctx, HORZ_LIST); + + lctx.send_dashes(); sql_free_result(mdb); db_unlock(mdb); @@ -466,7 +486,9 @@ db_list_files_for_job(JCR *jcr, B_DB *mdb, JobId_t jobid, DB_LIST_HANDLER *sendi void db_list_base_files_for_job(JCR *jcr, B_DB *mdb, JobId_t jobid, DB_LIST_HANDLER *sendit, void *ctx) { + LIST_CTX lctx(jcr, mdb, sendit, ctx, HORZ_LIST); char ed1[50]; + db_lock(mdb); /* @@ -490,12 +512,12 @@ db_list_base_files_for_job(JCR *jcr, B_DB *mdb, JobId_t jobid, DB_LIST_HANDLER * edit_int64(jobid, ed1)); } - if (!QUERY_DB(jcr, mdb, mdb->cmd)) { + if (!db_big_sql_query(mdb, mdb->cmd, list_result, &lctx)) { db_unlock(mdb); return; } - list_result(jcr, mdb, sendit, ctx, HORZ_LIST); + lctx.send_dashes(); sql_free_result(mdb); db_unlock(mdb); -- 2.39.5