X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fcats%2Fmysql.c;h=a7dfe465a5fe35575af74ef9be146fcc15ea8f10;hb=057312b2302ae774d35cd41e7ff5a682df841c0b;hp=98bd085a268b34f9b186f6c18148e746b29e4551;hpb=b2df60889338ba89879911ea5d45f087d7dc4de1;p=bacula%2Fbacula diff --git a/bacula/src/cats/mysql.c b/bacula/src/cats/mysql.c index 98bd085a26..a7dfe465a5 100644 --- a/bacula/src/cats/mysql.c +++ b/bacula/src/cats/mysql.c @@ -1,12 +1,12 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2007 Free Software Foundation Europe e.V. + Copyright (C) 2000-2010 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. This program is Free Software; you can redistribute it and/or - modify it under the terms of version two of the GNU General Public + modify it under the terms of version three of the GNU Affero General Public License as published by the Free Software Foundation and included in the file LICENSE. @@ -15,12 +15,12 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Affero General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Bacula® is a registered trademark of John Walker. + Bacula® is a registered trademark of Kern Sibbald. The licensor of Bacula is the Free Software Foundation Europe (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. @@ -32,7 +32,6 @@ * * Kern Sibbald, March 2000 * - * Version $Id$ */ @@ -54,7 +53,7 @@ */ /* List of open databases */ -static BQUEUE db_list = {&db_list, &db_list}; +static dlist *db_list = NULL; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; @@ -76,16 +75,19 @@ db_init_database(JCR *jcr, const char *db_name, const char *db_user, const char const char *db_address, int db_port, const char *db_socket, int mult_db_connections) { - B_DB *mdb; + B_DB *mdb = NULL; if (!db_user) { Jmsg(jcr, M_FATAL, 0, _("A user name for MySQL must be supplied.\n")); return NULL; } P(mutex); /* lock DB queue */ + if (db_list == NULL) { + db_list = New(dlist(mdb, &mdb->link)); + } /* Look to see if DB already open */ if (!mult_db_connections) { - for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) { + foreach_dlist(mdb, db_list) { if (bstrcmp(mdb->db_name, db_name) && bstrcmp(mdb->db_address, db_address) && mdb->db_port == db_port) { @@ -113,7 +115,6 @@ db_init_database(JCR *jcr, const char *db_name, const char *db_user, const char mdb->db_socket = bstrdup(db_socket); } mdb->db_port = db_port; - mdb->have_insert_id = true; mdb->errmsg = get_pool_memory(PM_EMSG); /* get error message buffer */ *mdb->errmsg = 0; mdb->cmd = get_pool_memory(PM_EMSG); /* get command buffer */ @@ -124,7 +125,9 @@ db_init_database(JCR *jcr, const char *db_name, const char *db_user, const char mdb->path = get_pool_memory(PM_FNAME); mdb->esc_name = get_pool_memory(PM_FNAME); mdb->esc_path = get_pool_memory(PM_FNAME); - qinsert(&db_list, &mdb->bq); /* put db in list */ + mdb->esc_obj = get_pool_memory(PM_FNAME); + mdb->allow_transactions = mult_db_connections; + db_list->append(mdb); /* put db in list */ Dmsg3(100, "initdb ref=%d connected=%d db=%p\n", mdb->ref_count, mdb->connected, mdb->db); V(mutex); @@ -149,8 +152,9 @@ db_open_database(JCR *jcr, B_DB *mdb) } if ((errstat=rwl_init(&mdb->lock)) != 0) { + berrno be; Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"), - strerror(errstat)); + be.bstrerror(errstat)); V(mutex); return 0; } @@ -191,6 +195,14 @@ db_open_database(JCR *jcr, B_DB *mdb) "Database=%s User=%s\n" "MySQL connect failed either server not running or your authorization is incorrect.\n"), mdb->db_name, mdb->db_user); +#if MYSQL_VERSION_ID >= 40101 + Dmsg3(50, "Error %u (%s): %s\n", + mysql_errno(&(mdb->mysql)), mysql_sqlstate(&(mdb->mysql)), + mysql_error(&(mdb->mysql))); +#else + Dmsg2(50, "Error %u: %s\n", + mysql_errno(&(mdb->mysql)), mysql_error(&(mdb->mysql))); +#endif V(mutex); return 0; } @@ -204,6 +216,10 @@ db_open_database(JCR *jcr, B_DB *mdb) Dmsg3(100, "opendb ref=%d connected=%d db=%p\n", mdb->ref_count, mdb->connected, mdb->db); + /* Set connection timeout to 8 days specialy for batch mode */ + sql_query(mdb, "SET wait_timeout=691200"); + sql_query(mdb, "SET interactive_timeout=691200"); + V(mutex); return 1; } @@ -221,7 +237,7 @@ db_close_database(JCR *jcr, B_DB *mdb) Dmsg3(100, "closedb ref=%d connected=%d db=%p\n", mdb->ref_count, mdb->connected, mdb->db); if (mdb->ref_count == 0) { - qdchain(&mdb->bq); + db_list->remove(mdb); if (mdb->connected) { Dmsg1(100, "close db=%p\n", mdb->db); mysql_close(&mdb->mysql); @@ -238,6 +254,7 @@ db_close_database(JCR *jcr, B_DB *mdb) free_pool_memory(mdb->path); free_pool_memory(mdb->esc_name); free_pool_memory(mdb->esc_path); + free_pool_memory(mdb->esc_obj); if (mdb->db_name) { free(mdb->db_name); } @@ -254,10 +271,24 @@ db_close_database(JCR *jcr, B_DB *mdb) free(mdb->db_socket); } free(mdb); + if (db_list->size() == 0) { + delete db_list; + db_list = NULL; + } } V(mutex); } +void db_check_backend_thread_safe() +{ +#ifdef HAVE_BATCH_FILE_INSERT + if (!mysql_thread_safe()) { + Emsg0(M_ABORT, 0, _("MySQL client library must be thread-safe " + "when using BatchMode.\n")); + } +#endif +} + /* * This call is needed because the message channel thread * opens a database on behalf of a jcr that was created in @@ -286,6 +317,36 @@ int db_next_index(JCR *jcr, B_DB *mdb, char *table, char *index) return 1; } +/* + * Escape binary object so that MySQL is happy + * Memory is stored in B_DB struct, no need to free it + */ +char * +db_escape_object(JCR *jcr, B_DB *mdb, char *old, int len) +{ + mdb->esc_obj = check_pool_memory_size(mdb->esc_obj, len*2+1); + mysql_real_escape_string(mdb->db, mdb->esc_obj, old, len); + return mdb->esc_obj; +} + +/* + * Unescape binary object so that MySQL is happy + */ +void +db_unescape_object(JCR *jcr, B_DB *db, + char *from, int32_t expected_len, + POOLMEM **dest, int32_t *dest_len) +{ + if (!from) { + *dest[0] = 0; + *dest_len = 0; + return; + } + *dest = check_pool_memory_size(*dest, expected_len+1); + *dest_len = expected_len; + memcpy(*dest, from, expected_len); + (*dest)[expected_len]=0; +} /* * Escape strings so that MySQL is happy @@ -304,7 +365,7 @@ db_escape_string(JCR *jcr, B_DB *mdb, char *snew, char *old, int len) * Submit a general SQL command (cmd), and for each row returned, * the sqlite_handler is called with the ctx. */ -int db_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handler, void *ctx) +bool db_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handler, void *ctx) { SQL_ROW row; bool send = true; @@ -313,7 +374,7 @@ int db_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handler if (sql_query(mdb, query) != 0) { Mmsg(mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror(mdb)); db_unlock(mdb); - return 0; + return false; } if (result_handler != NULL) { if ((mdb->result = sql_use_result(mdb)) != NULL) { @@ -336,7 +397,7 @@ int db_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handler } } db_unlock(mdb); - return 1; + return true; } @@ -350,35 +411,47 @@ void my_mysql_free_result(B_DB *mdb) db_unlock(mdb); } +uint64_t my_mysql_insert_autokey_record(B_DB *mdb, const char *query, const char *table_name) +{ + /* + * First execute the insert query and then retrieve the currval. + */ + if (mysql_query(mdb->db, query)) { + return 0; + } + + mdb->num_rows = sql_affected_rows(mdb); + if (mdb->num_rows != 1) { + return 0; + } + + mdb->changes++; + + return mysql_insert_id(mdb->db); +} + + #ifdef HAVE_BATCH_FILE_INSERT -char *my_mysql_batch_lock_path_query = "LOCK TABLES Path write, " - " batch write, " - " Path as p write "; - - -char *my_mysql_batch_lock_filename_query = "LOCK TABLES Filename write, " - " batch write, " - " Filename as f write "; - -char *my_mysql_batch_unlock_tables_query = "UNLOCK TABLES"; - -char *my_mysql_batch_fill_path_query = "INSERT INTO Path (Path) " - " SELECT a.Path FROM " - " (SELECT DISTINCT Path " - " FROM batch) AS a " - " WHERE NOT EXISTS " - " (SELECT Path " - " FROM Path AS p " - " WHERE p.Path = a.Path) "; - -char *my_mysql_batch_fill_filename_query = "INSERT INTO Filename (Name) " - " SELECT a.Name FROM " - " (SELECT DISTINCT Name " - " FROM batch) AS a " - " WHERE NOT EXISTS " - " (SELECT Name " - " FROM Filename AS f " - " WHERE f.Name = a.Name) "; +const char *my_mysql_batch_lock_path_query = + "LOCK TABLES Path write, batch write, Path as p write"; + + +const char *my_mysql_batch_lock_filename_query = + "LOCK TABLES Filename write, batch write, Filename as f write"; + +const char *my_mysql_batch_unlock_tables_query = "UNLOCK TABLES"; + +const char *my_mysql_batch_fill_path_query = + "INSERT INTO Path (Path) " + "SELECT a.Path FROM " + "(SELECT DISTINCT Path FROM batch) AS a WHERE NOT EXISTS " + "(SELECT Path FROM Path AS p WHERE p.Path = a.Path)"; + +const char *my_mysql_batch_fill_filename_query = + "INSERT INTO Filename (Name) " + "SELECT a.Name FROM " + "(SELECT DISTINCT Name FROM batch) AS a WHERE NOT EXISTS " + "(SELECT Name FROM Filename AS f WHERE f.Name = a.Name)"; #endif /* HAVE_BATCH_FILE_INSERT */ #endif /* HAVE_MYSQL */