sql: use transaction in Contact::add_or_lookup()

This commit is contained in:
link2xt
2023-02-19 15:01:33 +00:00
parent 9389e11007
commit 446214fd7b
2 changed files with 122 additions and 114 deletions

View File

@@ -3,6 +3,7 @@
## Unreleased ## Unreleased
### Changes ### Changes
- use transaction in `Contact::add_or_lookup()` #4059
### Fixes ### Fixes

View File

@@ -13,6 +13,7 @@ use async_channel::{self as channel, Receiver, Sender};
use deltachat_derive::{FromSql, ToSql}; use deltachat_derive::{FromSql, ToSql};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use rusqlite::OptionalExtension;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::task; use tokio::task;
use tokio::time::{timeout, Duration}; use tokio::time::{timeout, Duration};
@@ -520,8 +521,6 @@ impl Contact {
/// Depending on the origin, both, "row_name" and "row_authname" are updated from "name". /// Depending on the origin, both, "row_name" and "row_authname" are updated from "name".
/// ///
/// Returns the contact_id and a `Modifier` value indicating if a modification occurred. /// Returns the contact_id and a `Modifier` value indicating if a modification occurred.
///
/// Returns None if the contact with such address cannot exist.
pub(crate) async fn add_or_lookup( pub(crate) async fn add_or_lookup(
context: &Context, context: &Context,
name: &str, name: &str,
@@ -566,14 +565,12 @@ impl Contact {
); );
let mut update_addr = false; let mut update_addr = false;
let mut row_id = 0;
if let Some((id, row_name, row_addr, row_origin, row_authname)) = context let row_id = context.sql.transaction(|transaction| {
.sql let row = transaction.query_row(
.query_row_optional( "SELECT id, name, addr, origin, authname
"SELECT id, name, addr, origin, authname \ FROM contacts WHERE addr=? COLLATE NOCASE",
FROM contacts WHERE addr=? COLLATE NOCASE;", [addr.to_string()],
paramsv![addr.to_string()],
|row| { |row| {
let row_id: isize = row.get(0)?; let row_id: isize = row.get(0)?;
let row_name: String = row.get(1)?; let row_name: String = row.get(1)?;
@@ -582,10 +579,10 @@ impl Contact {
let row_authname: String = row.get(4)?; let row_authname: String = row.get(4)?;
Ok((row_id, row_name, row_addr, row_origin, row_authname)) Ok((row_id, row_name, row_addr, row_origin, row_authname))
}, }).optional()?;
)
.await? let row_id;
{ if let Some((id, row_name, row_addr, row_origin, row_authname)) = row {
let update_name = manual && name != row_name; let update_name = manual && name != row_name;
let update_authname = !manual let update_authname = !manual
&& name != row_authname && name != row_authname
@@ -605,8 +602,7 @@ impl Contact {
row_name row_name
}; };
context transaction
.sql
.execute( .execute(
"UPDATE contacts SET name=?, addr=?, origin=?, authname=? WHERE id=?;", "UPDATE contacts SET name=?, addr=?, origin=?, authname=? WHERE id=?;",
paramsv![ paramsv![
@@ -628,37 +624,50 @@ impl Contact {
}, },
row_id row_id
], ],
) )?;
.await
.ok();
if update_name || update_authname { if update_name || update_authname {
// Update the contact name also if it is used as a group name. // Update the contact name also if it is used as a group name.
// This is one of the few duplicated data, however, getting the chat list is easier this way. // This is one of the few duplicated data, however, getting the chat list is easier this way.
let chat_id: Option<i32> = context.sql.query_get_value( let chat_id: Option<ChatId> = transaction.query_row(
"SELECT id FROM chats WHERE type=? AND id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?)", "SELECT id FROM chats WHERE type=? AND id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?)",
paramsv![Chattype::Single, isize::try_from(row_id)?] params![Chattype::Single, isize::try_from(row_id)?],
).await?; |row| {
let chat_id: ChatId = row.get(0)?;
Ok(chat_id)
}
).optional()?;
if let Some(chat_id) = chat_id { if let Some(chat_id) = chat_id {
let contact = Contact::get_by_id(context, ContactId::new(row_id)).await?; let contact_id = ContactId::new(row_id);
let chat_name = contact.get_display_name(); let (addr, name, authname) =
match context transaction.query_row(
.sql "SELECT addr, name, authname
.execute( FROM contacts
"UPDATE chats SET name=?1 WHERE id=?2 AND name!=?3", WHERE id=?",
paramsv![chat_name, chat_id, chat_name], params![contact_id],
) |row| {
.await let addr: String = row.get(0)?;
{ let name: String = row.get(1)?;
Err(err) => warn!(context, "Can't update chat name: {}", err), let authname: String = row.get(2)?;
Ok(count) => { Ok((addr, name, authname))
})?;
let chat_name = if !name.is_empty() {
name
} else if !authname.is_empty() {
authname
} else {
addr
};
let count = transaction.execute(
"UPDATE chats SET name=?1 WHERE id=?2 AND name!=?1",
params![chat_name, chat_id])?;
if count > 0 { if count > 0 {
// Chat name updated // Chat name updated
context.emit_event(EventType::ChatModified(ChatId::new( context.emit_event(EventType::ChatModified(chat_id));
chat_id.try_into()?,
)));
}
}
} }
} }
} }
@@ -668,11 +677,11 @@ impl Contact {
let update_name = manual; let update_name = manual;
let update_authname = !manual; let update_authname = !manual;
if let Ok(new_row_id) = context transaction
.sql .execute(
.insert( "INSERT INTO contacts (name, addr, origin, authname)
"INSERT INTO contacts (name, addr, origin, authname) VALUES(?, ?, ?, ?);", VALUES (?, ?, ?, ?);",
paramsv![ params![
if update_name { if update_name {
name.to_string() name.to_string()
} else { } else {
@@ -686,16 +695,14 @@ impl Contact {
"".to_string() "".to_string()
} }
], ],
) )?;
.await
{
row_id = u32::try_from(new_row_id)?;
sth_modified = Modifier::Created; sth_modified = Modifier::Created;
row_id = u32::try_from(transaction.last_insert_rowid())?;
info!(context, "added contact id={} addr={}", row_id, &addr); info!(context, "added contact id={} addr={}", row_id, &addr);
} else {
error!(context, "Cannot add contact.");
}
} }
Ok(row_id)
}).await?;
Ok((ContactId::new(row_id), sth_modified)) Ok((ContactId::new(row_id), sth_modified))
} }