From: Eric Bollengier Date: Wed, 22 Sep 2021 15:00:13 +0000 (+0200) Subject: Add bconsole interface to metaxxx tables and rename Client.Plugin to Client.Plugins X-Git-Tag: Beta-15.0.0~873 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=068886d4df298456b95b34ef3dd485d87cd6db24;p=thirdparty%2Fbacula.git Add bconsole interface to metaxxx tables and rename Client.Plugin to Client.Plugins --- diff --git a/bacula/src/cats/bdb.h b/bacula/src/cats/bdb.h index ce09305d6..12719decb 100644 --- a/bacula/src/cats/bdb.h +++ b/bacula/src/cats/bdb.h @@ -149,6 +149,7 @@ public: bool bdb_check_settings(JCR *jcr, int64_t *starttime, int val1, int64_t val2); bool bdb_open_batch_connexion(JCR *jcr); bool bdb_check_max_connections(JCR *jcr, uint32_t max_concurrent_jobs); + virtual const char *search_op(JCR *jcr, const char *table_col, char *value, POOLMEM **esc, POOLMEM **dest); /* Acl parts for various SQL commands */ void free_acl(); /* Used internally, free acls tab */ @@ -279,7 +280,7 @@ public: void bdb_list_snapshot_records(JCR *jcr, SNAPSHOT_DBR *sdbr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type); void bdb_list_files(JCR *jcr, FILE_DBR *fr, DB_RESULT_HANDLER *sendit, void *ctx); - + void bdb_list_metadata_records(JCR *jcr, META_DBR *meta_r, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type); /* sql_update.c */ bool bdb_update_job_start_record(JCR *jcr, JOB_DBR *jr); int bdb_update_job_end_record(JCR *jcr, JOB_DBR *jr); diff --git a/bacula/src/cats/bdb_postgresql.h b/bacula/src/cats/bdb_postgresql.h index c552c2bc5..a098c9153 100644 --- a/bacula/src/cats/bdb_postgresql.h +++ b/bacula/src/cats/bdb_postgresql.h @@ -59,6 +59,7 @@ public: bool sql_batch_start(JCR *jcr); bool sql_batch_end(JCR *jcr, const char *error); bool sql_batch_insert(JCR *jcr, ATTR_DBR *ar); + const char *search_op(JCR *jcr, const char *table_col, char *value, POOLMEM **esc, POOLMEM **dest); }; #endif /* __BDB_POSTGRESQL_H_ */ diff --git a/bacula/src/cats/cats.c b/bacula/src/cats/cats.c index 8e102be15..eed9b5237 100644 --- a/bacula/src/cats/cats.c +++ b/bacula/src/cats/cats.c @@ -1,7 +1,7 @@ -/* +/* Bacula(R) - The Network Backup Solution - Copyright (C) 2000-2022 Kern Sibbald + Copyright (C) 2000-2023 Kern Sibbald The original author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -14,26 +14,26 @@ This notice must be preserved when any source code is conveyed and/or propagated. - Bacula(R) is a registered trademark of Kern Sibbald. -*/ -/* - * Generic catalog class methods. - * - * Note: at one point, this file was assembled from parts of other files - * by a programmer, and other than "wrapping" in a class, which is a trivial - * change for a C++ programmer, nothing substantial was done, yet all the - * code was recommitted under this programmer's name. Consequently, we - * undo those changes here. - */ - -#include "bacula.h" - -#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL - -#include "cats.h" + Bacula(R) is a registered trademark of Kern Sibbald. +*/ +/* + * Generic catalog class methods. + * + * Note: at one point, this file was assembled from parts of other files + * by a programmer, and other than "wrapping" in a class, which is a trivial + * change for a C++ programmer, nothing substantial was done, yet all the + * code was recommitted under this programmer's name. Consequently, we + * undo those changes here. + */ + +#include "bacula.h" + +#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL + +#include "cats.h" static int dbglvl=100; - + void append_filter(POOLMEM **buf, char *cond) { if (*buf[0] != '\0') { @@ -45,122 +45,141 @@ void append_filter(POOLMEM **buf, char *cond) pm_strcat(buf, cond); } -bool BDB::bdb_match_database(const char *db_driver, const char *db_name, - const char *db_address, int db_port) +static void append_AND_OR_filter(bool and_or, POOLMEM **buf, char *cond) { - BDB *mdb = this; - bool match; - - if (db_driver) { - match = strcasecmp(mdb->m_db_driver, db_driver) == 0 && - bstrcmp(mdb->m_db_name, db_name) && - bstrcmp(mdb->m_db_address, db_address) && - mdb->m_db_port == db_port && - mdb->m_dedicated == false; + if (*buf[0] != '\0') { + if (and_or) { + pm_strcat(buf, " OR "); + } else { + pm_strcat(buf, " AND "); + } } else { - match = bstrcmp(mdb->m_db_name, db_name) && - bstrcmp(mdb->m_db_address, db_address) && - mdb->m_db_port == db_port && - mdb->m_dedicated == false; + if (and_or) { + pm_strcpy(buf, " WHERE ( "); + } else { + pm_strcat(buf, " WHERE "); + } } - return match; + + pm_strcat(buf, cond); } -BDB *BDB::bdb_clone_database_connection(JCR *jcr, bool mult_db_connections) -{ - BDB *mdb = this; - /* - * See if its a simple clone e.g. with mult_db_connections set to false - * then we just return the calling class pointer. - */ - if (!mult_db_connections) { - mdb->m_ref_count++; - return mdb; - } - - /* - * A bit more to do here just open a new session to the database. - */ - return db_init_database(jcr, mdb->m_db_driver, mdb->m_db_name, +bool BDB::bdb_match_database(const char *db_driver, const char *db_name, + const char *db_address, int db_port) +{ + BDB *mdb = this; + bool match; + + if (db_driver) { + match = strcasecmp(mdb->m_db_driver, db_driver) == 0 && + bstrcmp(mdb->m_db_name, db_name) && + bstrcmp(mdb->m_db_address, db_address) && + mdb->m_db_port == db_port && + mdb->m_dedicated == false; + } else { + match = bstrcmp(mdb->m_db_name, db_name) && + bstrcmp(mdb->m_db_address, db_address) && + mdb->m_db_port == db_port && + mdb->m_dedicated == false; + } + return match; +} + +BDB *BDB::bdb_clone_database_connection(JCR *jcr, bool mult_db_connections) +{ + BDB *mdb = this; + /* + * See if its a simple clone e.g. with mult_db_connections set to false + * then we just return the calling class pointer. + */ + if (!mult_db_connections) { + mdb->m_ref_count++; + return mdb; + } + + /* + * A bit more to do here just open a new session to the database. + */ + return db_init_database(jcr, mdb->m_db_driver, mdb->m_db_name, mdb->m_db_user, mdb->m_db_password, mdb->m_db_address, mdb->m_db_port, mdb->m_db_socket, mdb->m_db_ssl_mode, mdb->m_db_ssl_key, mdb->m_db_ssl_cert, mdb->m_db_ssl_ca, mdb->m_db_ssl_capath, mdb->m_db_ssl_cipher, true, mdb->m_disabled_batch_insert); -} - -const char *BDB::bdb_get_engine_name(void) -{ - BDB *mdb = this; - switch (mdb->m_db_driver_type) { - case SQL_DRIVER_TYPE_MYSQL: - return "MySQL"; - case SQL_DRIVER_TYPE_POSTGRESQL: - return "PostgreSQL"; - case SQL_DRIVER_TYPE_SQLITE3: - return "SQLite3"; - default: - return "Unknown"; - } -} - -/* - * Lock database, this can be called multiple times by the same - * thread without blocking, but must be unlocked the number of - * times it was locked using db_unlock(). - */ -void BDB::bdb_lock(const char *file, int line) -{ - int errstat; - BDB *mdb = this; - - if ((errstat = rwl_writelock_p(&mdb->m_lock, file, line)) != 0) { - berrno be; - e_msg(file, line, M_FATAL, 0, "rwl_writelock failure. stat=%d: ERR=%s\n", - errstat, be.bstrerror(errstat)); - } -} - -/* - * Unlock the database. This can be called multiple times by the - * same thread up to the number of times that thread called - * db_lock()/ - */ -void BDB::bdb_unlock(const char *file, int line) -{ - int errstat; - BDB *mdb = this; - - if ((errstat = rwl_writeunlock(&mdb->m_lock)) != 0) { - berrno be; - e_msg(file, line, M_FATAL, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n", - errstat, be.bstrerror(errstat)); - } -} - -bool BDB::bdb_sql_query(const char *query, int flags) -{ - bool retval; - BDB *mdb = this; - - bdb_lock(); - retval = sql_query(query, flags); - if (!retval) { - Mmsg(mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror()); - } - bdb_unlock(); - return retval; -} - -void BDB::print_lock_info(FILE *fp) -{ - BDB *mdb = this; - if (mdb->m_lock.valid == RWLOCK_VALID) { - fprintf(fp, "\tRWLOCK=%p w_active=%i w_wait=%i\n", - &mdb->m_lock, mdb->m_lock.w_active, mdb->m_lock.w_wait); - } -} +} + +const char *BDB::bdb_get_engine_name(void) +{ + BDB *mdb = this; + switch (mdb->m_db_driver_type) { + case SQL_DRIVER_TYPE_MYSQL: + return "MySQL"; + case SQL_DRIVER_TYPE_POSTGRESQL: + return "PostgreSQL"; + case SQL_DRIVER_TYPE_SQLITE3: + return "SQLite3"; + default: + return "Unknown"; + } +} + +/* + * Lock database, this can be called multiple times by the same + * thread without blocking, but must be unlocked the number of + * times it was locked using db_unlock(). + */ +void BDB::bdb_lock(const char *file, int line) +{ + int errstat; + BDB *mdb = this; + + if ((errstat = rwl_writelock_p(&mdb->m_lock, file, line)) != 0) { + berrno be; + e_msg(file, line, M_FATAL, 0, "rwl_writelock failure. stat=%d: ERR=%s\n", + errstat, be.bstrerror(errstat)); + } +} + +/* + * Unlock the database. This can be called multiple times by the + * same thread up to the number of times that thread called + * db_lock()/ + */ +void BDB::bdb_unlock(const char *file, int line) +{ + int errstat; + BDB *mdb = this; + + if ((errstat = rwl_writeunlock(&mdb->m_lock)) != 0) { + berrno be; + e_msg(file, line, M_FATAL, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n", + errstat, be.bstrerror(errstat)); + } +} + +bool BDB::bdb_sql_query(const char *query, int flags) +{ + bool retval; + BDB *mdb = this; + + bdb_lock(); + retval = sql_query(query, flags); + if (!retval) { + Mmsg(mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror()); + } + bdb_unlock(); + return retval; +} + +void BDB::print_lock_info(FILE *fp) +{ + BDB *mdb = this; + if (mdb->m_lock.valid == RWLOCK_VALID) { + fprintf(fp, "\tRWLOCK=%p w_active=%i w_wait=%i\n", + &mdb->m_lock, mdb->m_lock.w_active, mdb->m_lock.w_wait); + } +} bool OBJECT_DBR::parse_plugin_object_string(char **obj_str) { @@ -245,8 +264,7 @@ bool OBJECT_DBR::parse_plugin_object_string(char **obj_str) if (!tmp) { goto bail_out; } - val = str_to_uint64(tmp); - ObjectCount = (val > 9223372036854775808ULL /*2^63 */) ? 0 : val; + ObjectCount = str_to_uint64(*obj_str); ret = true; @@ -336,7 +354,6 @@ void OBJECT_DBR::create_db_filter(JCR *jcr, POOLMEM **where) append_filter(where, tmp.c_str()); } } - } void parse_restore_object_string(char **r_obj_str, ROBJECT_DBR *robj_r) @@ -455,6 +472,7 @@ static struct json_sql email_json_v1[] = { SAME_KW("EmailImportance", OT_STRING), SAME_KW("EmailInternetMessageId", OT_STRING), SAME_KW("EmailIsRead", OT_BOOL), + SAME_KW("EmailIsDraft", OT_BOOL), SAME_KW("EmailTime", OT_STRING), SAME_KW("EmailSubject", OT_STRING), SAME_KW("EmailTags", OT_STRING), @@ -633,5 +651,153 @@ bail_out: return status; } +void META_DBR::get_important_keys(POOLMEM **where) +{ + if (bstrcasecmp(Type, "email")) { + Mmsg(where, "EmailTenant, EmailOwner, EmailFrom, EmailTo, EmailTime, EmailSubject, FileIndex, JobId"); + } else { + Mmsg(where, "AttachmentEmailId, AttachmentSize, AttachmentName, FileIndex, JobId"); + } +} + +void META_DBR::get_all_keys(POOLMEM **where) +{ + struct json_sql *p; + if (bstrcasecmp(Type, "email")) { + p = email_json_v1; + } else { + p = email_attachment_json_v1; + } + + Mmsg(where, "JobId,FileIndex"); + for (int i = 0; p[i].sql_name ; i++) { + pm_strcat(where, ","); + pm_strcat(where, p[i].sql_name); + } +} + +void META_DBR::create_db_filter(JCR *jcr, BDB *db, POOLMEM **where) +{ + const char *prefix; + bool and_or = false; + POOL_MEM esc(PM_MESSAGE), tmp(PM_MESSAGE); + + if (bstrcasecmp(Type, "email")) { + prefix = "Email"; + } else { + prefix = "Attachment"; + } + + if (bstrcasecmp(Type, "email")) + { + if (all && (*From || *To || *Cc || *Subject || *Tags || *BodyPreview || *Category)) { + and_or = true; + } + + if (Id[0] != 0) { + db->search_op(jcr, "MetaEmail.EmailId", Id, esc.handle(), tmp.handle()); + append_AND_OR_filter(and_or, where, tmp.c_str()); + } + + if (From[0] != 0) { + db->search_op(jcr, "MetaEmail.EmailFrom", From, esc.handle(), tmp.handle()); + append_AND_OR_filter(and_or, where, tmp.c_str()); + } + + if (To[0] != 0) { + db->search_op(jcr, "MetaEmail.EmailTo", To, esc.handle(), tmp.handle()); + append_AND_OR_filter(and_or, where, tmp.c_str()); + } + + if (Cc[0] != 0) { + db->search_op(jcr, "MetaEmail.EmailCc", Cc, esc.handle(), tmp.handle()); + append_AND_OR_filter(and_or, where, tmp.c_str()); + } + + if (Subject[0] != 0) { + db->search_op(jcr, "MetaEmail.EmailSubject", Subject, esc.handle(), tmp.handle()); + append_AND_OR_filter(and_or, where, tmp.c_str()); + } + + if (Tags[0] != 0) { + db->search_op(jcr, "MetaEmail.EmailTags", Tags, esc.handle(), tmp.handle()); + append_AND_OR_filter(and_or, where, tmp.c_str()); + } + + if (BodyPreview[0] != 0) { + db->search_op(jcr, "MetaEmail.EmailBodyPreview", BodyPreview, esc.handle(), tmp.handle()); + append_AND_OR_filter(and_or, where, tmp.c_str()); + } +#if 0 + if (Category[0] != 0) { + db->search_op(jcr, "MetaEmail.EmailCategory", Category, esc.handle(), tmp.handle()); + append_AND_OR_filter(and_or, where, tmp.c_str()); + } +#endif + + if (and_or) { + pm_strcat(where, ") "); + } + + if (ConversationId[0] != 0) { + db_escape_string(jcr, jcr->db, esc.c_str(), ConversationId, strlen(ConversationId)); + Mmsg(tmp, " MetaEmail.EmailConversationId = '%s'", esc.c_str()); + append_filter(where, tmp.c_str()); + } + + if (HasAttachment > 0) { + Mmsg(tmp, " MetaEmail.EmailHasAttachment = %d", HasAttachment); + append_filter(where, tmp.c_str()); + } + + if (isDraft > 0) { + Mmsg(tmp, " MetaEmail.EmailIsDraft = %d", isDraft); + append_filter(where, tmp.c_str()); + } + + if (isRead > 0) { + Mmsg(tmp, " MetaEmail.EmailIsRead = %d", isRead); + append_filter(where, tmp.c_str()); + } + + if (MinTime[0]) { + db_escape_string(jcr, jcr->db, esc.c_str(), MinTime, strlen(MinTime)); + Mmsg(tmp, " MetaEmail.EmailTime >= '%s'", esc.c_str()); + append_filter(where, tmp.c_str()); + } + + if (MaxTime[0]) { + db_escape_string(jcr, jcr->db, esc.c_str(), MaxTime, strlen(MaxTime)); + Mmsg(tmp, " MetaEmail.EmailTime <= '%s'", esc.c_str()); + append_filter(where, tmp.c_str()); + } + } else { + if (Id[0] != 0) { + db->search_op(jcr, "MetaAttachment.AttachmentEmailId", Id, esc.handle(), tmp.handle()); + append_AND_OR_filter(and_or, where, tmp.c_str()); + } + } + + if (MinSize > 0) { + Mmsg(tmp, " Meta%s.%sSize >= %llu", prefix, prefix, MinSize); + append_filter(where, tmp.c_str()); + } + + if (MaxSize > 0) { + Mmsg(tmp, " Meta%s.%sSize <= %llu", prefix, prefix, MaxSize); + append_filter(where, tmp.c_str()); + } + + if (Plugin[0] != 0) { + db_escape_string(jcr, jcr->db, esc.c_str(), Plugin, strlen(Plugin)); + Mmsg(tmp, " Meta%s.Plugin='%s'", prefix, esc.c_str()); + append_filter(where, tmp.c_str()); + } + + if (JobId != 0) { + Mmsg(tmp, " Meta%s.JobId=%lu", prefix, JobId); + append_filter(where, tmp.c_str()); + } +} #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */ diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index a8381b010..74c3d66d5 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -484,7 +484,7 @@ struct CLIENT_DBR { utime_t JobRetention; char Name[MAX_NAME_LENGTH]; /* Client name */ char Uname[MAX_UNAME_LENGTH]; /* Uname for client */ - char Plugin[MAX_PLUGIN_LENGTH]; /* Plugin list for this client */ + char Plugins[MAX_PLUGIN_LENGTH]; /* Plugin list for this client */ }; /* Counter record as in database */ @@ -630,6 +630,57 @@ public: uint64_t *aclbits_extra); /* Extra ACL used */ }; + + +/* Used to search in MetaEmail and MetaAttachment table */ +#define MAX_SEARCH_LENGTH 256 +#define MAX_SEARCH_LENGTH_ESCAPED (MAX_SEARCH_LENGTH * 2 + 1) + +class META_DBR: public SMARTALLOC +{ +public: + JobId_t JobId; + int64_t MinSize; + int64_t MaxSize; + int HasAttachment; + int isDraft; + int isRead; + uint64_t offset; + uint32_t limit; + int order; + int orderby; // 0: JobId, FileIndex 1: EmailTime + bool all; + + char Id[MAX_SEARCH_LENGTH]; + char Tenant[MAX_SEARCH_LENGTH]; + char Owner[MAX_SEARCH_LENGTH]; + char ClientName[MAX_NAME_LENGTH]; + char From[MAX_SEARCH_LENGTH]; + char To[MAX_SEARCH_LENGTH]; + char Cc[MAX_SEARCH_LENGTH]; + char Tags[MAX_SEARCH_LENGTH]; + char Subject[MAX_SEARCH_LENGTH]; + char BodyPreview[MAX_SEARCH_LENGTH]; + char Type[16]; // Email or Attachment + char ConversationId[MAX_NAME_LENGTH]; + char Category[MAX_SEARCH_LENGTH]; + char MinTime[MAX_NAME_LENGTH]; + char MaxTime[MAX_NAME_LENGTH]; + char Plugin[MAX_NAME_LENGTH]; + META_DBR(): JobId(0), MinSize(-1), MaxSize(-1), HasAttachment(-1), + isDraft(-1), isRead(-1), offset(0), limit(512), order(0), orderby(0), all(false) + { + *Id = *Tenant = *Owner = 0; + *ClientName = *From = *To = *Cc = *Subject = *Tags = 0; + *BodyPreview = *Type = *ConversationId = *Category = 0; + *MinTime = *MaxTime = *Plugin = 0; + }; + ~META_DBR() {}; + void get_important_keys(POOLMEM **dest); + void get_all_keys(POOLMEM **dest); + void create_db_filter(JCR *jcr, BDB *db, POOLMEM **dest); +}; + /* Call back context for getting a 32/64 bit value from the database */ class db_int64_ctx { public: diff --git a/bacula/src/cats/postgresql.c b/bacula/src/cats/postgresql.c index aaac8bc35..45abf0125 100644 --- a/bacula/src/cats/postgresql.c +++ b/bacula/src/cats/postgresql.c @@ -1186,5 +1186,13 @@ bool BDB_POSTGRESQL::sql_batch_insert(JCR *jcr, ATTR_DBR *ar) return true; } +const char *BDB_POSTGRESQL::search_op(JCR *jcr, const char *table_col, char *value, POOLMEM **esc, POOLMEM **dest) +{ + int len = strlen(value); + *esc = check_pool_memory_size(*esc, len*2+1); + bdb_escape_string(jcr, *esc, value, len); + Mmsg(dest, " %s %%> '%s'", table_col, *esc); + return *dest; +} #endif /* HAVE_POSTGRESQL */ diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index 28ff00cc1..a598447f7 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -309,6 +309,8 @@ void bdb_free_restoreobject_record(JCR *jcr, ROBJECT_DBR *rr); mdb->bdb_list_files(jcr, filedbr, sendit, ua); #define db_list_tag_records(jcr, mdb, tagdbr, sendit, ua, llist) \ mdb->bdb_list_tag_records(jcr, tagdbr, sendit, ua, llist); +#define db_list_metadata_records(jcr, mdb, dbr, sendit, ua, llist) \ + mdb->bdb_list_metadata_records(jcr, dbr, sendit, ua, llist); /* sql_update.c */ #define db_update_job_start_record(jcr, mdb, jr) \ diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c index b8dcadc7b..1ad740c2c 100644 --- a/bacula/src/cats/sql.c +++ b/bacula/src/cats/sql.c @@ -1413,6 +1413,15 @@ void TAG_DBR::gen_sql(JCR *jcr, BDB *db, *aclbits_extra_ = aclbits_extra; } +const char *BDB::search_op(JCR *jcr, const char *table_col, char *value, POOLMEM **esc, POOLMEM **dest) +{ + int len = strlen(value); + *esc = check_pool_memory_size(*esc, len*2+1); + bdb_escape_string(jcr, *esc, (char*)value, len); + Mmsg(dest, " %s ILIKE '%%%s%%'", table_col, value); + return *dest; +} + #ifdef COMMUNITY bool BDB::bdb_check_settings(JCR *jcr, int64_t *starttime, int val, int64_t val2) { diff --git a/bacula/src/cats/sql_list.c b/bacula/src/cats/sql_list.c index d8f4ad16c..9167a629f 100644 --- a/bacula/src/cats/sql_list.c +++ b/bacula/src/cats/sql_list.c @@ -1,7 +1,7 @@ /* Bacula(R) - The Network Backup Solution - Copyright (C) 2000-2022 Kern Sibbald + Copyright (C) 2000-2023 Kern Sibbald The original author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -39,7 +39,7 @@ /* * Submit general SQL query */ -int BDB::bdb_list_sql_query(JCR *jcr, const char *title, const char *query, DB_LIST_HANDLER *sendit, +int BDB::bdb_list_sql_query(JCR *jcr, const char *query, DB_LIST_HANDLER *sendit, void *ctx, int verbose, e_list_type type) { bdb_lock(); @@ -52,7 +52,7 @@ int BDB::bdb_list_sql_query(JCR *jcr, const char *title, const char *query, DB_L return 0; } - list_result(jcr,this, title, sendit, ctx, type); + list_result(jcr,this, sendit, ctx, type); sql_free_result(); bdb_unlock(); return 1; @@ -100,7 +100,7 @@ void BDB::bdb_list_pool_records(JCR *jcr, POOL_DBR *pdbr, return; } - list_result(jcr, this, "pool", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); sql_free_result(); bdb_unlock(); @@ -110,19 +110,19 @@ void BDB::bdb_list_client_records(JCR *jcr, DB_LIST_HANDLER *sendit, void *ctx, { bdb_lock(); if (type == VERT_LIST || type == JSON_LIST) { - Mmsg(cmd, "SELECT ClientId,Name,Uname,Plugin,AutoPrune,FileRetention," + Mmsg(cmd, "SELECT ClientId,Name,Uname,Plugins,AutoPrune,FileRetention," "JobRetention " - "FROM Client %s ORDER BY ClientId", get_acls(DB_ACL_BIT(DB_ACL_RBCLIENT), true)); + "FROM Client %s ORDER BY ClientId", get_acl(DB_ACL_CLIENT, true)); } else { Mmsg(cmd, "SELECT ClientId,Name,FileRetention,JobRetention " - "FROM Client %s ORDER BY ClientId", get_acls(DB_ACL_BIT(DB_ACL_RBCLIENT), true)); + "FROM Client %s ORDER BY ClientId", get_acl(DB_ACL_CLIENT, true)); } if (!QueryDB(jcr, cmd)) { bdb_unlock(); return; } - list_result(jcr, this, "client", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); sql_free_result(); bdb_unlock(); @@ -144,7 +144,7 @@ void BDB::bdb_list_plugin_object_types(JCR *jcr, DB_LIST_HANDLER *sendit, void * return; } - list_result(jcr, this, "objecttype", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); sql_free_result(); bdb_unlock(); @@ -204,7 +204,7 @@ void BDB::bdb_list_plugin_objects(JCR *jcr, OBJECT_DBR *obj_r, DB_LIST_HANDLER * return; } - list_result(jcr, this, "object", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); sql_free_result(); bdb_unlock(); @@ -244,7 +244,7 @@ void BDB::bdb_list_plugin_objects_ids(JCR *jcr, char* id_list, DB_LIST_HANDLER * return; } - list_result(jcr, this, "object", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); sql_free_result(); bdb_unlock(); @@ -296,7 +296,7 @@ void BDB::bdb_list_restore_objects(JCR *jcr, ROBJECT_DBR *rr, DB_LIST_HANDLER *s return; } - list_result(jcr, this, "restoreobject", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); sql_free_result(); bdb_unlock(); @@ -385,7 +385,7 @@ void BDB::bdb_list_media_records(JCR *jcr, MEDIA_DBR *mdbr, return; } - list_result(jcr, this, "media", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); sql_free_result(); bdb_unlock(); @@ -396,30 +396,25 @@ void BDB::bdb_list_jobmedia_records(JCR *jcr, uint32_t JobId, char *volume, { POOL_MEM where2; bdb_lock(); - const char *where_and = "WHERE"; - /* Get some extra SQL parameters if needed */ const char *where = get_acls(DB_ACL_BIT(DB_ACL_JOB) | DB_ACL_BIT(DB_ACL_FILESET) | - DB_ACL_BIT(DB_ACL_BCLIENT), true); + DB_ACL_BIT(DB_ACL_CLIENT), (JobId == 0 || volume != NULL)); const char *join = *where ? get_acl_join_filter(DB_ACL_BIT(DB_ACL_JOB) | DB_ACL_BIT(DB_ACL_FILESET) | - DB_ACL_BIT(DB_ACL_BCLIENT)) : ""; + DB_ACL_BIT(DB_ACL_CLIENT)) : ""; - if (*where) { - where_and = "AND"; - } if (JobId) { - Mmsg(where2, " %s JobMedia.JobId=%lu ", where_and, JobId); - where_and = "AND"; + Mmsg(where2, " WHERE JobMedia.JobId=%lu ", JobId); } + if (volume) { POOL_MEM tmp, tmp2; int len = strlen(volume); tmp.check_size(len*2+1); db_escape_string(jcr, this, tmp.c_str(), volume, len); - Mmsg(tmp2, " %s Media.VolumeName = '%s' ", where_and, tmp.c_str()); + Mmsg(tmp2, " %s Media.VolumeName = '%s' ", JobId == 0 ?"WHERE": "AND", tmp.c_str()); pm_strcat(where2, tmp2.c_str()); } @@ -430,15 +425,15 @@ void BDB::bdb_list_jobmedia_records(JCR *jcr, uint32_t JobId, char *volume, "FROM JobMedia JOIN Media USING (MediaId) %s " "%s %s ORDER BY JobMediaId ASC", join, - where, - where2.c_str()); + where2.c_str(), + where); } else { Mmsg(cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex " "FROM JobMedia JOIN Media USING (MediaId) %s %s %s ORDER BY JobMediaId ASC", join, - where, - where2.c_str()); + where2.c_str(), + where); } Dmsg1(DT_SQL|50, "q=%s\n", cmd); @@ -447,7 +442,7 @@ void BDB::bdb_list_jobmedia_records(JCR *jcr, uint32_t JobId, char *volume, return; } - list_result(jcr, this, "jobmedia", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); sql_free_result(); bdb_unlock(); @@ -484,12 +479,13 @@ void BDB::bdb_list_filemedia_records(JCR *jcr, uint32_t JobId, uint32_t FileInde return; } - list_result(jcr, this, "filemedia", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); sql_free_result(); bdb_unlock(); } + void BDB::bdb_list_copies_records(JCR *jcr, uint32_t limit, char *JobIds, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { @@ -506,8 +502,8 @@ void BDB::bdb_list_copies_records(JCR *jcr, uint32_t limit, char *JobIds, } bdb_lock(); - const char *where = get_acls(DB_ACL_BIT(DB_ACL_JOB) | DB_ACL_BIT(DB_ACL_BCLIENT), false); - const char *join = *where ? get_acl_join_filter(DB_ACL_BIT(DB_ACL_BCLIENT)) : ""; + const char *where = get_acls(DB_ACL_BIT(DB_ACL_JOB) | DB_ACL_BIT(DB_ACL_CLIENT), false); + const char *join = *where ? get_acl_join_filter(DB_ACL_BIT(DB_ACL_CLIENT)) : ""; Mmsg(cmd, "SELECT DISTINCT Job.PriorJobId AS JobId, Job.Job, " @@ -529,7 +525,7 @@ void BDB::bdb_list_copies_records(JCR *jcr, uint32_t limit, char *JobIds, sendit(ctx, _("The catalog contains copies as follows:\n")); } - list_result(jcr, this, "copy", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); } sql_free_result(); @@ -631,7 +627,7 @@ void BDB::bdb_list_events_records(JCR *jcr, EVENTS_DBR *rec, if (!QueryDB(jcr, cmd)) { goto bail_out; } - list_result(jcr, this, "event", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); bail_out: bdb_unlock(); @@ -649,13 +645,12 @@ void BDB::bdb_list_joblog_records(JCR *jcr, uint32_t JobId, const char *where = get_acls(DB_ACL_BIT(DB_ACL_JOB) | DB_ACL_BIT(DB_ACL_FILESET) | - DB_ACL_BIT(DB_ACL_RBCLIENT) - , false); + DB_ACL_BIT(DB_ACL_CLIENT), false); const char *join = *where ? get_acl_join_filter(DB_ACL_BIT(DB_ACL_JOB) | DB_ACL_BIT(DB_ACL_FILESET) | - DB_ACL_BIT(DB_ACL_RBCLIENT)) : ""; - + DB_ACL_BIT(DB_ACL_CLIENT)) : ""; + if (type == VERT_LIST || type == JSON_LIST) { Mmsg(cmd, "SELECT Time,LogText FROM Log %s " "WHERE Log.JobId=%s %s ORDER BY LogId ASC", @@ -675,7 +670,7 @@ void BDB::bdb_list_joblog_records(JCR *jcr, uint32_t JobId, goto bail_out; } - list_result(jcr, this, "joblog", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); sql_free_result(); @@ -773,7 +768,7 @@ alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, pm_strcat(where, where_tmp); if (*where_tmp) { - join = get_acl_join_filter(DB_ACL_BIT(DB_ACL_RBCLIENT) | + join = get_acl_join_filter(DB_ACL_BIT(DB_ACL_CLIENT) | DB_ACL_BIT(DB_ACL_FILESET)); } @@ -785,7 +780,7 @@ alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, "Job.ClientId,Client.Name as ClientName,JobStatus,SchedTime," "StartTime,EndTime,RealEndTime,JobTDate," "VolSessionId,VolSessionTime,JobFiles,JobBytes,ReadBytes,JobErrors," - "JobMissingFiles,Job.PoolId,Pool.Name as PoolName,PriorJobId,PriorJob," + "JobMissingFiles,Job.PoolId,Pool.Name as PoolName,PriorJobId," "Job.FileSetId,FileSet.FileSet,Job.HasCache,Comment,Reviewed " "FROM Job JOIN Client USING (ClientId) LEFT JOIN Pool USING (PoolId) " "LEFT JOIN FileSet USING (FileSetId) %s " @@ -802,13 +797,6 @@ alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, "FROM Job %s %s ORDER BY StartTime %s,JobId %s %s", join, where, order, order, limit); break; - case LAST_JOBS: - Mmsg(cmd, - "SELECT JobId,Client1.Name as Client,Job.Name as Name,StartTime,Level as " - "JobLevel,JobFiles,JobBytes " - "FROM Client AS Client1 JOIN Job USING (ClientId) %s %s AND JobStatus IN ('T','W') " - "ORDER BY StartTime %s %s", join, where, order, limit); - default: break; } @@ -830,7 +818,7 @@ alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, } } sql_data_seek(0); - list_result(jcr, this, "job", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); sql_free_result(); bdb_unlock(); return list; @@ -839,13 +827,12 @@ alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, /* * List Job totals * - * TODO: Adapt for JSON */ void BDB::bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx) { bdb_lock(); - const char *where = get_acls(DB_ACL_BIT(DB_ACL_BCLIENT) | DB_ACL_BIT(DB_ACL_JOB), true); - const char *join = *where ? get_acl_join_filter(DB_ACL_BIT(DB_ACL_BCLIENT)) : ""; + const char *where = get_acls(DB_ACL_BIT(DB_ACL_CLIENT) | DB_ACL_BIT(DB_ACL_JOB), true); + const char *join = *where ? get_acl_join_filter(DB_ACL_BIT(DB_ACL_CLIENT)) : ""; /* List by Job */ Mmsg(cmd, "SELECT count(*) AS Jobs,sum(JobFiles) " @@ -857,7 +844,7 @@ void BDB::bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, vo return; } - list_result(jcr, this, "jobtotal", sendit, ctx, HORZ_LIST); + list_result(jcr, this, sendit, ctx, HORZ_LIST); sql_free_result(); @@ -871,7 +858,7 @@ void BDB::bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, vo return; } - list_result(jcr, this, "jobtotal", sendit, ctx, HORZ_LIST); + list_result(jcr, this, sendit, ctx, HORZ_LIST); sql_free_result(); bdb_unlock(); @@ -901,11 +888,11 @@ void BDB::bdb_list_files_for_job(JCR *jcr, JobId_t jobid, int deleted, DB_LIST_H bdb_lock(); /* Get optional filters for the SQL query */ const char *where = get_acls(DB_ACL_BIT(DB_ACL_JOB) | - DB_ACL_BIT(DB_ACL_BCLIENT) | + DB_ACL_BIT(DB_ACL_CLIENT) | DB_ACL_BIT(DB_ACL_FILESET), true); const char *join = *where ? get_acl_join_filter(DB_ACL_BIT(DB_ACL_JOB) | - DB_ACL_BIT(DB_ACL_BCLIENT) | + DB_ACL_BIT(DB_ACL_CLIENT) | DB_ACL_BIT(DB_ACL_FILESET)) : ""; /* @@ -990,7 +977,7 @@ void BDB::bdb_list_snapshot_records(JCR *jcr, SNAPSHOT_DBR *sdbr, char ed1[50]; bdb_lock(); - const char *where = get_acl(DB_ACL_BCLIENT, false); + const char *where = get_acl(DB_ACL_CLIENT, false); *filter = 0; if (sdbr->Name[0]) { @@ -1068,7 +1055,7 @@ void BDB::bdb_list_snapshot_records(JCR *jcr, SNAPSHOT_DBR *sdbr, goto bail_out; } - list_result(jcr, this, "snapshot", sendit, ctx, type); + list_result(jcr, this, sendit, ctx, type); bail_out: sql_free_result(); @@ -1142,60 +1129,79 @@ void BDB::bdb_list_tag_records(JCR *jcr, TAG_DBR *tag, DB_LIST_HANDLER *result_h } } Dmsg1(DT_SQL|50, "q=%s\n", tmp.c_str()); - bdb_list_sql_query(jcr, "tag", tmp.c_str(), result_handler, ctx, 0, type); + bdb_list_sql_query(jcr, tmp.c_str(), result_handler, ctx, 0, type); } bdb_unlock(); } -/* List all file records from a job - * "deleted" values are described just below +/* + * List plugin objects (search is based on object provided) */ -void BDB::bdb_list_jobs_for_file(JCR *jcr, const char *client, const char *fname, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) +void BDB::bdb_list_metadata_records(JCR *jcr, META_DBR *meta_r, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type) { - if (!client || !*client || !fname || !*fname) { - return; + POOL_MEM esc(PM_MESSAGE), tmp(PM_MESSAGE), where(PM_MESSAGE), join(PM_MESSAGE); + + bdb_lock(); + + //TODO add ACL part + meta_r->create_db_filter(jcr, this, where.handle()); + Dmsg1(DT_SQL|50, "where=[%s]\n", where.c_str()); + + if (meta_r->ClientName[0] != 0) { + bdb_escape_string(jcr, esc.c_str(), meta_r->ClientName, strlen(meta_r->ClientName)); + Mmsg(tmp, " Client.Name='%s'", esc.c_str()); + append_filter(where.handle(), tmp.c_str()); + Mmsg(join, " JOIN Job USING (JobId) JOIN Client USING (ClientId) "); } - const char *concat="Path.Path||File.Filename"; - if (bdb_get_type_index() == SQL_TYPE_MYSQL) { - concat = " CONCAT(Path.Path,File.Filename) "; + if (meta_r->orderby == 1) { + Mmsg(tmp, " ORDER BY EmailTime %s ", meta_r->order ? "DESC" : "ASC"); + } else { + Mmsg(tmp, " ORDER BY JobId, FileIndex %s ", meta_r->order ? "DESC" : "ASC"); } - bdb_lock(); - /* Get optional filters for the SQL query */ - const char *where = get_acls(DB_ACL_BIT(DB_ACL_JOB) | - DB_ACL_BIT(DB_ACL_BCLIENT) | - DB_ACL_BIT(DB_ACL_FILESET), false); + pm_strcat(where, tmp.c_str()); - const char *join = *where ? get_acl_join_filter(DB_ACL_BIT(DB_ACL_FILESET)) : ""; - - int len = strlen(fname); - char *esc = (char *)malloc(len * 2 + 1); - bdb_escape_string(jcr, esc, (char *)fname, len); - - len = strlen(client); - char *esc2 = (char *)malloc(len * 2 + 1); - bdb_escape_string(jcr, esc2, (char *)client, len); - - Mmsg(cmd, "SELECT Job.JobId as JobId," - "%s as Name, " // Concat of the filename - "StartTime, Type as JobType, JobStatus,JobFiles,JobBytes " - "FROM Client JOIN Job USING (ClientId) JOIN File USING (JobId) JOIN Path USING (PathId) %s " - "WHERE Client.Name = '%s' " - "AND File.FileIndex > 0 " - "AND File.Filename='%s' %s ORDER BY StartTime DESC LIMIT 20", concat, join, esc2, esc, where); - - free(esc); - free(esc2); - Dmsg1(DT_SQL|50, "q=%s\n", cmd); + if (meta_r->limit > 0) { + Mmsg(tmp, " LIMIT %d ", meta_r->limit); + pm_strcat(where, tmp.c_str()); + } + + if (meta_r->offset > 0) { + Mmsg(tmp, " OFFSET %ld ", meta_r->offset); + pm_strcat(where, tmp.c_str()); + } + + switch (type) { + case JSON_LIST: + case VERT_LIST: + meta_r->get_all_keys(tmp.handle()); + Mmsg(cmd, + "SELECT %s " + "FROM Meta%s %s %s", tmp.c_str(), meta_r->Type, join.c_str(), where.c_str()); + break; + case HORZ_LIST: + meta_r->get_important_keys(tmp.handle()); + Mmsg(cmd, + "SELECT %s " + "FROM Meta%s %s %s", tmp.c_str(), meta_r->Type, join.c_str(), where.c_str()); + break; + default: + break; + } + Dmsg1(DT_SQL|50, "%s\n", cmd); if (!QueryDB(jcr, cmd)) { - goto bail_out; + Jmsg(jcr, M_ERROR, 0, _("Query %s failed!\n"), cmd); + bdb_unlock(); + return; } - list_result(jcr, this, "job", sendit, ctx, HORZ_LIST); -bail_out: + list_result(jcr, this, sendit, ctx, type); + sql_free_result(); bdb_unlock(); + } + #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */ diff --git a/bacula/src/cats/sql_update.c b/bacula/src/cats/sql_update.c index af93c7459..76a6db1e6 100644 --- a/bacula/src/cats/sql_update.c +++ b/bacula/src/cats/sql_update.c @@ -217,11 +217,11 @@ int BDB::bdb_update_client_record(JCR *jcr, CLIENT_DBR *cr) bdb_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name)); bdb_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname)); - bdb_escape_string(jcr, esc_plugin, cr->Plugin, strlen(cr->Plugin)); + bdb_escape_string(jcr, esc_plugin, cr->Plugins, strlen(cr->Plugins)); Mmsg(cmd, "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s," -"Uname='%s',Plugin='%s' WHERE Name='%s'", +"Uname='%s',Plugins='%s' WHERE Name='%s'", cr->AutoPrune, edit_uint64(cr->FileRetention, ed1), edit_uint64(cr->JobRetention, ed2), diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index f6a566d0c..0ecfa321c 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -657,7 +657,7 @@ static void update_attribute(JCR *jcr, char *msg, int32_t msglen) meta_pkt mp(p); META_JSON parser; POOL_MEM val; - Dmsg3(50, "[metadata plugin] type=%d len=%d buf=[%.*s]\n", mp.type, mp.buf_len, mp.buf); + Dmsg4(150, "[metadata plugin] type=%d len=%d buf=[%.*s]\n", mp.type, mp.buf_len, mp.buf_len, mp.buf); if (parser.parse(jcr, jcr->db, jcr->wjcr? jcr->wjcr->JobId : jcr->JobId, @@ -673,7 +673,7 @@ static void update_attribute(JCR *jcr, char *msg, int32_t msglen) } db_unlock(jcr->db); } else { - Jmsg1(jcr, M_ERROR, 0, _("Unable to parse Plugin metadata for FileIndex %lld\n"), (int64_t)FileIndex); + Jmsg(jcr, M_ERROR, 0, _("Unable to parse Plugin metadata for FileIndex %lld\n"), (int64_t)FileIndex); Dmsg1(50, "Unable to parse Plugin metadata err=%s\n", val.c_str()); } diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c index 7e57b759b..83d014e88 100644 --- a/bacula/src/dird/fd_cmds.c +++ b/bacula/src/dird/fd_cmds.c @@ -199,7 +199,7 @@ int connect_to_file_daemon(JCR *jcr, int retry_interval, int max_retry_time, char *pos = strchr(fd->msg+strlen(OKjob)+1, ';'); if (pos) { *pos = 0; - bstrncpy(cr.Plugin, pos+1, sizeof(cr.Plugin)); + bstrncpy(cr.Plugins, pos+1, sizeof(cr.Plugins)); } bstrncpy(cr.Uname, fd->msg+strlen(OKjob)+1, sizeof(cr.Uname)); diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c index ecf323e35..0a84c17a0 100644 --- a/bacula/src/dird/ua_output.c +++ b/bacula/src/dird/ua_output.c @@ -336,10 +336,14 @@ bail_out: * list objects [type=objecttype job_id=id clientname=n,status=S] - list plugin objects * list pluginrestoreconf jobid=x,y,z [id=k] * list filemedia jobid=x fileindex=z - * list metadata type=email [search= where= importance= isread= isdraft= hasattachement= limit= offset= receivedtime=