void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& host, std::string const& user, std::string const& password, std::string const& port_or_socket, std::string const& database, Path const& path) { std::vector<std::string> args; args.reserve(7); // CLI Client connection info args.push_back("-h" + host); args.push_back("-u" + user); args.push_back("-p" + password); args.push_back("-P" + port_or_socket); // Set the default charset to utf8 args.push_back("--default-character-set=utf8"); // Set max allowed packet to 1 GB args.push_back("--max-allowed-packet=1GB"); // Database if (!database.empty()) args.push_back(database); // ToDo: use the existing query in memory as virtual file if possible file_descriptor_source source(path); uint32 ret; try { child c = execute(run_exe(DBUpdater<T>::GetMySqlCli().empty() ? "mysql" : boost::filesystem::absolute(DBUpdater<T>::GetMySqlCli()).generic_string()), set_args(args), bind_stdin(source), throw_on_error()); ret = wait_for_exit(c); } catch (boost::system::system_error&) { ret = EXIT_FAILURE; } source.close(); if (ret != EXIT_SUCCESS) { TC_LOG_FATAL("sql.updates", "Applying of file \'%s\' to database \'%s\' failed!" \ " If you are an user pull the latest revision from the repository. If you are a developer fix your sql query.", path.generic_string().c_str(), pool.GetConnectionInfo()->database.c_str()); throw UpdateException("update failed"); } }
bool DBUpdater<T>::Create(DatabaseWorkerPool<T>& pool) { TC_LOG_INFO("sql.updates", "Database \"%s\" does not exist, do you want to create it? [yes (default) / no]: ", pool.GetConnectionInfo()->database.c_str()); std::string answer; std::getline(std::cin, answer); if (!answer.empty() && !(answer.substr(0, 1) == "y")) return false; TC_LOG_INFO("sql.updates", "Creating database \"%s\"...", pool.GetConnectionInfo()->database.c_str()); // Path of temp file static Path const temp("create_table.sql"); // Create temporary query to use external mysql cli std::ofstream file(temp.generic_string()); if (!file.is_open()) { TC_LOG_FATAL("sql.updates", "Failed to create temporary query file \"%s\"!", temp.generic_string().c_str()); return false; } file << "CREATE DATABASE `" << pool.GetConnectionInfo()->database << "` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci\n\n"; file.close(); try { DBUpdater<T>::ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user, pool.GetConnectionInfo()->password, pool.GetConnectionInfo()->port_or_socket, "", temp); } catch (UpdateException&) { TC_LOG_FATAL("sql.updates", "Failed to create database %s! Has the user `CREATE` priviliges?", pool.GetConnectionInfo()->database.c_str()); boost::filesystem::remove(temp); return false; } TC_LOG_INFO("sql.updates", "Done."); boost::filesystem::remove(temp); return true; }
void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& host, std::string const& user, std::string const& password, std::string const& port_or_socket, std::string const& database, Path const& path) { std::vector<std::string> args; args.reserve(8); // args[0] represents the program name args.push_back("mysql"); // CLI Client connection info args.push_back("-h" + host); args.push_back("-u" + user); if (!password.empty()) args.push_back("-p" + password); // Check if we want to connect through ip or socket (Unix only) #ifdef _WIN32 args.push_back("-P" + port_or_socket); #else if (!std::isdigit(port_or_socket[0])) { // We can't check here if host == "." because is named localhost if socket option is enabled args.push_back("-P0"); args.push_back("--protocol=SOCKET"); args.push_back("-S" + port_or_socket); } else // generic case args.push_back("-P" + port_or_socket); #endif // Set the default charset to utf8 args.push_back("--default-character-set=utf8"); // Set max allowed packet to 1 GB args.push_back("--max-allowed-packet=1GB"); // Database if (!database.empty()) args.push_back(database); // ToDo: use the existing query in memory as virtual file if possible file_descriptor_source source(path); uint32 ret; try { boost::process::pipe outPipe = create_pipe(); boost::process::pipe errPipe = create_pipe(); child c = execute(run_exe( boost::filesystem::absolute(DBUpdaterUtil::GetCorrectedMySQLExecutable()).generic_string()), set_args(args), bind_stdin(source), throw_on_error(), bind_stdout(file_descriptor_sink(outPipe.sink, close_handle)), bind_stderr(file_descriptor_sink(errPipe.sink, close_handle))); file_descriptor_source mysqlOutfd(outPipe.source, close_handle); file_descriptor_source mysqlErrfd(errPipe.source, close_handle); stream<file_descriptor_source> mysqlOutStream(mysqlOutfd); stream<file_descriptor_source> mysqlErrStream(mysqlErrfd); std::stringstream out; std::stringstream err; copy(mysqlOutStream, out); copy(mysqlErrStream, err); TC_LOG_INFO("sql.updates", "%s", out.str().c_str()); TC_LOG_ERROR("sql.updates", "%s", err.str().c_str()); ret = wait_for_exit(c); } catch (boost::system::system_error&) { ret = EXIT_FAILURE; } source.close(); if (ret != EXIT_SUCCESS) { TC_LOG_FATAL("sql.updates", "Applying of file \'%s\' to database \'%s\' failed!" \ " If you are an user pull the latest revision from the repository. If you are a developer fix your sql query.", path.generic_string().c_str(), pool.GetConnectionInfo()->database.c_str()); throw UpdateException("update failed"); } }
void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, Path const& path) { DBUpdater<T>::ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user, pool.GetConnectionInfo()->password, pool.GetConnectionInfo()->port_or_socket, pool.GetConnectionInfo()->database, path); }
void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& host, std::string const& user, std::string const& password, std::string const& port_or_socket, std::string const& database, Path const& path) { std::vector<std::string> args; args.reserve(8); // args[0] represents the program name args.push_back("mysql"); // CLI Client connection info args.push_back("-h" + host); args.push_back("-u" + user); if (!password.empty()) args.push_back("-p" + password); // Check if we want to connect through ip or socket (Unix only) #ifdef _WIN32 args.push_back("-P" + port_or_socket); #else if (!std::isdigit(port_or_socket[0])) { // We can't check if host == "." here, because it is named localhost if socket option is enabled args.push_back("-P0"); args.push_back("--protocol=SOCKET"); args.push_back("-S" + port_or_socket); } else // generic case args.push_back("-P" + port_or_socket); #endif // Set the default charset to utf8 args.push_back("--default-character-set=utf8"); // Set max allowed packet to 1 GB args.push_back("--max-allowed-packet=1GB"); // Database if (!database.empty()) args.push_back(database); // Invokes a mysql process which doesn't leak credentials to logs int const ret = Trinity::StartProcess(DBUpdaterUtil::GetCorrectedMySQLExecutable(), args, "sql.updates", path.generic_string(), true); if (ret != EXIT_SUCCESS) { TC_LOG_FATAL("sql.updates", "Applying of file \'%s\' to database \'%s\' failed!" \ " If you are a user, please pull the latest revision from the repository. " "Also make sure you have not applied any of the databases with your sql client. " "You cannot use auto-update system and import sql files from TrinityCore repository with your sql client. " "If you are a developer, please fix your sql query.", path.generic_string().c_str(), pool.GetConnectionInfo()->database.c_str()); throw UpdateException("update failed"); } }