Skip to content

Commit

Permalink
improve: use mysqldump for create database backup
Browse files Browse the repository at this point in the history
  • Loading branch information
dudantas committed Nov 12, 2024
1 parent 95a9d3e commit 5c988af
Showing 1 changed file with 24 additions and 109 deletions.
133 changes: 24 additions & 109 deletions src/database/database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,88 +61,6 @@ bool Database::connect(const std::string* host, const std::string* user, const s
return true;
}

namespace {
std::string createBackupFileName(const std::string &backupDir, const std::string &formattedTime) {
std::filesystem::create_directories(backupDir);
return fmt::format("{}/backup_{}.sql", backupDir, formattedTime);
}

MYSQL_RES* getTableList(MYSQL* handle) {
if (mysql_query(handle, "SHOW TABLES") != 0) {
g_logger().error("Failed to retrieve table list: {}", mysql_error(handle));
return nullptr;
}
return mysql_store_result(handle);
}

void writeCreateTableStatement(MYSQL* handle, const std::string &tableName, std::ofstream &backupFile) {
std::string createTableQuery = fmt::format("SHOW CREATE TABLE `{}`", tableName);
if (mysql_query(handle, createTableQuery.c_str()) == 0) {
MYSQL_RES* createTableResult = mysql_store_result(handle);
if (createTableResult) {
MYSQL_ROW createRow = mysql_fetch_row(createTableResult);
if (createRow && createRow[1]) {
backupFile << createRow[1] << ";\n\n";
}
mysql_free_result(createTableResult);
}
} else {
g_logger().error("Failed to retrieve create statement for table {}: {}", tableName, mysql_error(handle));
}
}

void writeValue(std::ofstream &backupFile, const char* value, const MYSQL_FIELD &field, unsigned long length) {
if (!value) {
backupFile << "NULL";
return;
}

if (IS_BLOB(field.type)) {
backupFile << g_database().escapeBlob(value, length);
} else if (IS_NUM(field.type)) {
backupFile << value;
} else {
backupFile << g_database().escapeString(std::string(value, length));
}
}

void writeTableData(MYSQL* handle, const std::string &tableName, std::ofstream &backupFile) {
std::string selectQuery = fmt::format("SELECT * FROM `{}`", tableName);
if (mysql_query(handle, selectQuery.c_str()) != 0) {
g_logger().error("Failed to retrieve data from table {}: {}", tableName, mysql_error(handle));
return;
}

MYSQL_RES* tableData = mysql_store_result(handle);
if (!tableData) {
g_logger().error("Failed to store data result for table {}: {}", tableName, mysql_error(handle));
return;
}

int numFields = mysql_num_fields(tableData);
MYSQL_FIELD* fields = mysql_fetch_fields(tableData);
MYSQL_ROW rowData;

while ((rowData = mysql_fetch_row(tableData))) {
auto lengths = mysql_fetch_lengths(tableData);
backupFile << "INSERT INTO " << tableName << " VALUES(";

for (int i = 0; i < numFields; ++i) {
if (i > 0) {
backupFile << ", ";
}

writeValue(backupFile, rowData[i], fields[i], lengths[i]);
}

backupFile << ");\n";
}

backupFile << "\n";
mysql_free_result(tableData);
}
}

void Database::createDatabaseBackup() const {
if (!g_configManager().getBoolean(MYSQL_DB_BACKUP)) {
return;
Expand All @@ -156,41 +74,38 @@ void Database::createDatabaseBackup() const {
return;
}

// Criar arquivo de backup
std::string backupDir = "database_backup/";
std::string backupFileName = createBackupFileName(backupDir, formattedTime);
std::ofstream backupFile(backupFileName, std::ios::binary);

if (!backupFile.is_open()) {
g_logger().error("Failed to open backup file: {}", backupFileName);
std::filesystem::create_directories(backupDir);
std::string backupFileName = fmt::format("{}/backup_{}.sql", backupDir, formattedTime);

std::string tempConfigFile = "database_backup.cnf";
std::ofstream configFile(tempConfigFile);
if (configFile.is_open()) {
configFile << "[client]\n";
configFile << "user=" << g_configManager().getString(MYSQL_USER) << "\n";
configFile << "password=" << g_configManager().getString(MYSQL_PASS) << "\n";
configFile << "host=" << g_configManager().getString(MYSQL_HOST) << "\n";
configFile << "port=" << g_configManager().getNumber(SQL_PORT) << "\n";
configFile.close();
} else {
g_logger().error("Failed to create temporary MySQL configuration file.");
return;
}

if (!handle) {
g_logger().error("Database handle not initialized.");
return;
}
std::string command = fmt::format(
"mysqldump --defaults-extra-file={} {} > {}",
tempConfigFile, g_configManager().getString(MYSQL_DB), backupFileName
);

// Obter a lista de tabelas
MYSQL_RES* tablesResult = getTableList(handle);
if (!tablesResult) {
return;
}
int result = std::system(command.c_str());

g_logger().info("Creating database backup...");
MYSQL_ROW tableRow;
std::filesystem::remove(tempConfigFile);

// Iterar sobre as tabelas e gravar suas informações no arquivo de backup
while ((tableRow = mysql_fetch_row(tablesResult))) {
std::string tableName = tableRow[0];
writeCreateTableStatement(handle, tableName, backupFile);
writeTableData(handle, tableName, backupFile);
if (result != 0) {
g_logger().error("Failed to create database backup using mysqldump.");
} else {
g_logger().info("Database backup successfully created at: {}", backupFileName);
}

mysql_free_result(tablesResult);
backupFile.close();

g_logger().info("Database backup successfully created at: {}", backupFileName);
}

bool Database::beginTransaction() {
Expand Down

0 comments on commit 5c988af

Please sign in to comment.