Delete expired messages using multiple SQL requests

With existing approach of constructing
the SQL query dynamically I get errors like this:
   ephemeral.rs:575: update failed: too many SQL variables: Error code 1: SQL error or missing database

In my case it is trying to delete 143658 messages.
This is the result of importing a Desktop backup
and enabling device auto-deletion on the phone.
Current SQLite limit is 32766 variables
as stated in <https://www.sqlite.org/limits.html>.
This commit is contained in:
link2xt
2023-03-15 11:00:20 +00:00
parent 6b67f8bcfd
commit cdd696db95
2 changed files with 30 additions and 26 deletions

View File

@@ -13,6 +13,7 @@
background process spawned by `dc_configure()` or `dc_imex()` background process spawned by `dc_configure()` or `dc_imex()`
or `dc_jsonrpc_instance_t` is unreferenced or `dc_jsonrpc_instance_t` is unreferenced
during handling the JSON-RPC request. #4153 during handling the JSON-RPC request. #4153
- Delete expired messages using multiple SQL requests. #4158
## 1.111.0 ## 1.111.0

View File

@@ -68,7 +68,7 @@ use std::num::ParseIntError;
use std::str::FromStr; use std::str::FromStr;
use std::time::{Duration, SystemTime, UNIX_EPOCH}; use std::time::{Duration, SystemTime, UNIX_EPOCH};
use anyhow::{ensure, Context as _, Result}; use anyhow::{ensure, Result};
use async_channel::Receiver; use async_channel::Receiver;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::time::timeout; use tokio::time::timeout;
@@ -433,37 +433,40 @@ pub(crate) async fn delete_expired_messages(context: &Context, now: i64) -> Resu
let rows = select_expired_messages(context, now).await?; let rows = select_expired_messages(context, now).await?;
if !rows.is_empty() { if !rows.is_empty() {
context info!(context, "Attempting to delete {} messages.", rows.len());
let (msgs_changed, webxdc_deleted) = context
.sql .sql
.execute( .transaction(|transaction| {
let mut msgs_changed = Vec::with_capacity(rows.len());
let mut webxdc_deleted = Vec::new();
// If you change which information is removed here, also change MsgId::trash() and // If you change which information is removed here, also change MsgId::trash() and
// which information receive_imf::add_parts() still adds to the db if the chat_id is TRASH // which information receive_imf::add_parts() still adds to the db if the chat_id is TRASH
&format!( for (msg_id, chat_id, viewtype) in rows {
r#" transaction.execute(
UPDATE msgs "UPDATE msgs
SET SET chat_id=?, txt='', subject='', txt_raw='',
chat_id=?, txt='', subject='', txt_raw='', mime_headers='', from_id=0, to_id=0, param=''
mime_headers='', from_id=0, to_id=0, param='' WHERE id=?",
WHERE id IN ({}) params![DC_CHAT_ID_TRASH, msg_id],
"#, )?;
sql::repeat_vars(rows.len())
),
rusqlite::params_from_iter(
std::iter::once(&DC_CHAT_ID_TRASH as &dyn crate::ToSql).chain(
rows.iter()
.map(|(msg_id, _chat_id, _viewtype)| msg_id as &dyn crate::ToSql),
),
),
)
.await
.context("update failed")?;
for (msg_id, chat_id, viewtype) in rows { msgs_changed.push((chat_id, msg_id));
if viewtype == Viewtype::Webxdc {
webxdc_deleted.push(msg_id)
}
}
Ok((msgs_changed, webxdc_deleted))
})
.await?;
for (chat_id, msg_id) in msgs_changed {
context.emit_msgs_changed(chat_id, msg_id); context.emit_msgs_changed(chat_id, msg_id);
}
if viewtype == Viewtype::Webxdc { for msg_id in webxdc_deleted {
context.emit_event(EventType::WebxdcInstanceDeleted { msg_id }); context.emit_event(EventType::WebxdcInstanceDeleted { msg_id });
}
} }
} }