From feecaa5400c0541370713703aa867a5ab7d4b96d Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 22 Dec 2024 18:50:40 +0000 Subject: [PATCH] fix: reduce number of repeat_vars() calls SQL statements fail if the number of variables exceeds `SQLITE_LIMIT_VARIABLE_NUMBER`. Remaining repeat_vars() calls are difficult to replace and use arrays passed from the UI, e.g. forwarded message IDs or marked as seen IDs. --- src/chat.rs | 17 ++++++++----- src/contact.rs | 19 ++++++-------- src/ephemeral.rs | 32 +++++++++++------------ src/imap.rs | 66 ++++++++++++++++++++++++------------------------ src/smtp.rs | 22 ++++++++-------- 5 files changed, 76 insertions(+), 80 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index 437dbff4ef..c23e1cba2d 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -3267,14 +3267,17 @@ pub async fn marknoticed_chat(context: &Context, chat_id: ChatId) -> Result<()> context .sql - .execute( - &format!( - "UPDATE msgs SET state=13 WHERE state=10 AND hidden=0 AND chat_id IN ({});", - sql::repeat_vars(chat_ids_in_archive.len()) - ), - rusqlite::params_from_iter(&chat_ids_in_archive), - ) + .transaction(|transaction| { + let mut stmt = transaction.prepare( + "UPDATE msgs SET state=13 WHERE state=10 AND hidden=0 AND chat_id = ?", + )?; + for chat_id_in_archive in &chat_ids_in_archive { + stmt.execute((chat_id_in_archive,))?; + } + Ok(()) + }) .await?; + for chat_id_in_archive in chat_ids_in_archive { context.emit_event(EventType::MsgsNoticed(chat_id_in_archive)); chatlist_events::emit_chatlist_item_changed(context, chat_id_in_archive); diff --git a/src/contact.rs b/src/contact.rs index 6ce4ecfa9f..06f153457c 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -129,17 +129,14 @@ impl ContactId { ) -> Result<()> { context .sql - .execute( - &format!( - "UPDATE contacts SET origin=? WHERE id IN ({}) AND origin Result<()> { let now = time(); - let count = context + let should_interrupt = + context .sql - .execute( - &format!( - "UPDATE msgs SET ephemeral_timestamp = ? + ephemeral_timer - WHERE (ephemeral_timestamp == 0 OR ephemeral_timestamp > ? + ephemeral_timer) AND ephemeral_timer > 0 - AND id IN ({})", - sql::repeat_vars(msg_ids.len()) - ), - rusqlite::params_from_iter( - std::iter::once(&now as &dyn crate::sql::ToSql) - .chain(std::iter::once(&now as &dyn crate::sql::ToSql)) - .chain(params_iter(msg_ids)), - ), - ) - .await?; - if count > 0 { + .transaction(move |transaction| { + let mut should_interrupt = false; + let mut stmt = + transaction.prepare( + "UPDATE msgs SET ephemeral_timestamp = ?1 + ephemeral_timer + WHERE (ephemeral_timestamp == 0 OR ephemeral_timestamp > ?1 + ephemeral_timer) AND ephemeral_timer > 0 + AND id=?2")?; + for msg_id in msg_ids { + should_interrupt |= stmt.execute((now, msg_id))? > 0; + } + Ok(should_interrupt) + }).await?; + if should_interrupt { context.scheduler.interrupt_ephemeral_task().await; } Ok(()) diff --git a/src/imap.rs b/src/imap.rs index 50a159b387..55df079e3a 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -46,7 +46,6 @@ use crate::receive_imf::{ from_field_to_contact_id, get_prefetch_parent_message, receive_imf_inner, ReceivedMsg, }; use crate::scheduler::connectivity::ConnectivityStore; -use crate::sql; use crate::stock_str; use crate::tools::{self, create_id, duration_to_str}; @@ -911,15 +910,15 @@ impl Session { .await?; context .sql - .execute( - &format!( - "DELETE FROM imap WHERE id IN ({})", - sql::repeat_vars(row_ids.len()) - ), - rusqlite::params_from_iter(row_ids), - ) + .transaction(|transaction| { + let mut stmt = transaction.prepare("DELETE FROM imap WHERE id = ?")?; + for row_id in row_ids { + stmt.execute((row_id,))?; + } + Ok(()) + }) .await - .context("cannot remove deleted messages from imap table")?; + .context("Cannot remove deleted messages from imap table")?; context.emit_event(EventType::ImapMessageDeleted(format!( "IMAP messages {uid_set} marked as deleted" @@ -942,15 +941,15 @@ impl Session { // Messages are moved or don't exist, IMAP returns OK response in both cases. context .sql - .execute( - &format!( - "DELETE FROM imap WHERE id IN ({})", - sql::repeat_vars(row_ids.len()) - ), - rusqlite::params_from_iter(row_ids), - ) + .transaction(|transaction| { + let mut stmt = transaction.prepare("DELETE FROM imap WHERE id = ?")?; + for row_id in row_ids { + stmt.execute((row_id,))?; + } + Ok(()) + }) .await - .context("cannot delete moved messages from imap table")?; + .context("Cannot delete moved messages from imap table")?; context.emit_event(EventType::ImapMessageMoved(format!( "IMAP messages {set} moved to {target}" ))); @@ -996,15 +995,15 @@ impl Session { } context .sql - .execute( - &format!( - "UPDATE imap SET target='' WHERE id IN ({})", - sql::repeat_vars(row_ids.len()) - ), - rusqlite::params_from_iter(row_ids), - ) + .transaction(|transaction| { + let mut stmt = transaction.prepare("UPDATE imap SET target='' WHERE id = ?")?; + for row_id in row_ids { + stmt.execute((row_id,))?; + } + Ok(()) + }) .await - .context("cannot plan deletion of messages")?; + .context("Cannot plan deletion of messages")?; if copy { context.emit_event(EventType::ImapMessageMoved(format!( "IMAP messages {set} copied to {target}" @@ -1147,15 +1146,16 @@ impl Session { ); context .sql - .execute( - &format!( - "DELETE FROM imap_markseen WHERE id IN ({})", - sql::repeat_vars(rowid_set.len()) - ), - rusqlite::params_from_iter(rowid_set), - ) + .transaction(|transaction| { + let mut stmt = + transaction.prepare("DELETE FROM imap_markseen WHERE id = ?")?; + for rowid in rowid_set { + stmt.execute((rowid,))?; + } + Ok(()) + }) .await - .context("cannot remove messages marked as seen from imap_markseen table")?; + .context("Cannot remove messages marked as seen from imap_markseen table")?; } } diff --git a/src/smtp.rs b/src/smtp.rs index 7bc51a2780..d25143c75e 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -21,7 +21,6 @@ use crate::mimefactory::MimeFactory; use crate::net::proxy::ProxyConfig; use crate::net::session::SessionBufStream; use crate::scheduler::connectivity::ConnectivityStore; -use crate::sql; use crate::stock_str::unencrypted_email; use crate::tools::{self, time_elapsed}; @@ -585,18 +584,17 @@ async fn send_mdn_rfc724_mid( info!(context, "Successfully sent MDN for {rfc724_mid}."); context .sql - .execute("DELETE FROM smtp_mdns WHERE rfc724_mid = ?", (rfc724_mid,)) + .transaction(|transaction| { + transaction + .execute("DELETE FROM smtp_mdns WHERE rfc724_mid = ?", (rfc724_mid,))?; + let mut stmt = + transaction.prepare("DELETE FROM smtp_mdns WHERE rfc724_mid = ?")?; + for additional_rfc724_mid in additional_rfc724_mids { + stmt.execute((additional_rfc724_mid,))?; + } + Ok(()) + }) .await?; - if !additional_rfc724_mids.is_empty() { - let q = format!( - "DELETE FROM smtp_mdns WHERE rfc724_mid IN({})", - sql::repeat_vars(additional_rfc724_mids.len()) - ); - context - .sql - .execute(&q, rusqlite::params_from_iter(additional_rfc724_mids)) - .await?; - } Ok(true) } SendResult::Retry => {