@@ -196,18 +196,16 @@ void Database::updateEmailContent(EmailData* data) {
196196 sqlite3_finalize (stmt);
197197}
198198
199- void Database::deleteEmailAttachments (int playerID, int index, int slot) {
200- std::lock_guard<std::mutex> lock (dbCrit);
201-
199+ static void _deleteEmailAttachments (int playerID, int index, int slot) {
202200 sqlite3_stmt* stmt;
203201
204202 std::string sql (R"(
205203 DELETE FROM EmailItems
206- WHERE PlayerID = ? AND MsgIndex = ?;
204+ WHERE PlayerID = ? AND MsgIndex = ?
207205 )" );
208206
209207 if (slot != -1 )
210- sql += " AND \" Slot\" = ? " ;
208+ sql += " AND \" Slot\" = ?" ;
211209 sql += " ;" ;
212210
213211 sqlite3_prepare_v2 (db, sql.c_str (), -1 , &stmt, NULL );
@@ -221,6 +219,11 @@ void Database::deleteEmailAttachments(int playerID, int index, int slot) {
221219 sqlite3_finalize (stmt);
222220}
223221
222+ void Database::deleteEmailAttachments (int playerID, int index, int slot) {
223+ std::lock_guard<std::mutex> lock (dbCrit);
224+ _deleteEmailAttachments (playerID, index, slot);
225+ }
226+
224227void Database::deleteEmails (int playerID, int64_t * indices) {
225228 std::lock_guard<std::mutex> lock (dbCrit);
226229
@@ -234,12 +237,15 @@ void Database::deleteEmails(int playerID, int64_t* indices) {
234237 sqlite3_prepare_v2 (db, sql, -1 , &stmt, NULL );
235238
236239 for (int i = 0 ; i < 5 ; i++) {
240+ int64_t msgIndex = indices[i];
237241 sqlite3_bind_int (stmt, 1 , playerID);
238- sqlite3_bind_int64 (stmt, 2 , indices[i] );
242+ sqlite3_bind_int64 (stmt, 2 , msgIndex );
239243 if (sqlite3_step (stmt) != SQLITE_DONE) {
240244 std::cout << " [WARN] Database: Failed to delete an email: " << sqlite3_errmsg (db) << std::endl;
241245 }
242246 sqlite3_reset (stmt);
247+ // delete all attachments
248+ _deleteEmailAttachments (playerID, msgIndex, -1 );
243249 }
244250 sqlite3_finalize (stmt);
245251
@@ -323,12 +329,23 @@ bool Database::sendEmail(EmailData* data, std::vector<sItemBase> attachments, Pl
323329 sqlite3_bind_int (stmt, 7 , item.iTimeLimit );
324330
325331 if (sqlite3_step (stmt) != SQLITE_DONE) {
326- std::cout << " [WARN] Database: Failed to send email: " << sqlite3_errmsg (db) << std::endl;
327- sqlite3_exec (db, " ROLLBACK TRANSACTION;" , NULL , NULL , NULL );
328- sqlite3_finalize (stmt);
329- return false ;
332+ // very likely the UNIQUE constraint failing due to
333+ // orphaned attachments from an old email.
334+ // try deleting them first
335+ _deleteEmailAttachments (data->PlayerId , data->MsgIndex , -1 );
336+
337+ // try again
338+ sqlite3_reset (stmt);
339+ if (sqlite3_step (stmt) != SQLITE_DONE) {
340+ // different error, give up
341+ std::cout << " [WARN] Database: Failed to send email: " << sqlite3_errmsg (db) << std::endl;
342+ sqlite3_exec (db, " ROLLBACK TRANSACTION;" , NULL , NULL , NULL );
343+ sqlite3_finalize (stmt);
344+ return false ;
345+ }
330346 }
331347 sqlite3_reset (stmt);
348+ sqlite3_clear_bindings (stmt);
332349 }
333350 sqlite3_finalize (stmt);
334351
0 commit comments