Fix email attachment collisions causing email send failure (#312)

This commit is contained in:
2025-12-07 16:38:46 -08:00
committed by GitHub
parent 8d0587dd45
commit 572df90645

View File

@@ -196,18 +196,16 @@ void Database::updateEmailContent(EmailData* data) {
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
} }
void Database::deleteEmailAttachments(int playerID, int index, int slot) { static void _deleteEmailAttachments(int playerID, int index, int slot) {
std::lock_guard<std::mutex> lock(dbCrit);
sqlite3_stmt* stmt; sqlite3_stmt* stmt;
std::string sql(R"( std::string sql(R"(
DELETE FROM EmailItems DELETE FROM EmailItems
WHERE PlayerID = ? AND MsgIndex = ?; WHERE PlayerID = ? AND MsgIndex = ?
)"); )");
if (slot != -1) if (slot != -1)
sql += " AND \"Slot\" = ? "; sql += " AND \"Slot\" = ?";
sql += ";"; sql += ";";
sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, NULL); sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, NULL);
@@ -221,6 +219,11 @@ void Database::deleteEmailAttachments(int playerID, int index, int slot) {
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
} }
void Database::deleteEmailAttachments(int playerID, int index, int slot) {
std::lock_guard<std::mutex> lock(dbCrit);
_deleteEmailAttachments(playerID, index, slot);
}
void Database::deleteEmails(int playerID, int64_t* indices) { void Database::deleteEmails(int playerID, int64_t* indices) {
std::lock_guard<std::mutex> lock(dbCrit); std::lock_guard<std::mutex> lock(dbCrit);
@@ -234,12 +237,15 @@ void Database::deleteEmails(int playerID, int64_t* indices) {
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
int64_t msgIndex = indices[i];
sqlite3_bind_int(stmt, 1, playerID); sqlite3_bind_int(stmt, 1, playerID);
sqlite3_bind_int64(stmt, 2, indices[i]); sqlite3_bind_int64(stmt, 2, msgIndex);
if (sqlite3_step(stmt) != SQLITE_DONE) { if (sqlite3_step(stmt) != SQLITE_DONE) {
std::cout << "[WARN] Database: Failed to delete an email: " << sqlite3_errmsg(db) << std::endl; std::cout << "[WARN] Database: Failed to delete an email: " << sqlite3_errmsg(db) << std::endl;
} }
sqlite3_reset(stmt); sqlite3_reset(stmt);
// delete all attachments
_deleteEmailAttachments(playerID, msgIndex, -1);
} }
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
@@ -323,12 +329,23 @@ bool Database::sendEmail(EmailData* data, std::vector<sItemBase> attachments, Pl
sqlite3_bind_int(stmt, 7, item.iTimeLimit); sqlite3_bind_int(stmt, 7, item.iTimeLimit);
if (sqlite3_step(stmt) != SQLITE_DONE) { if (sqlite3_step(stmt) != SQLITE_DONE) {
std::cout << "[WARN] Database: Failed to send email: " << sqlite3_errmsg(db) << std::endl; // very likely the UNIQUE constraint failing due to
sqlite3_exec(db, "ROLLBACK TRANSACTION;", NULL, NULL, NULL); // orphaned attachments from an old email.
sqlite3_finalize(stmt); // try deleting them first
return false; _deleteEmailAttachments(data->PlayerId, data->MsgIndex, -1);
// try again
sqlite3_reset(stmt);
if (sqlite3_step(stmt) != SQLITE_DONE) {
// different error, give up
std::cout << "[WARN] Database: Failed to send email: " << sqlite3_errmsg(db) << std::endl;
sqlite3_exec(db, "ROLLBACK TRANSACTION;", NULL, NULL, NULL);
sqlite3_finalize(stmt);
return false;
}
} }
sqlite3_reset(stmt); sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
} }
sqlite3_finalize(stmt); sqlite3_finalize(stmt);