Do not use grpid to find last inserted row in chats table

Instead, use last_insert_rowid() function to find the row.

There is no race condition in using last_insert_rowid(), because
last_insert_rowid() returns row id last inserted in this connection. As
we hold the connection during the whole transaction, it is impossible
that some other thread will execute INSERT statement in parallel.

This commit is part of the effort to get rid of sql::get_rowid hack and
use transactions more for related SQL statements.
This commit is contained in:
Alexander Krotov
2020-02-15 16:30:11 +03:00
parent 784964efad
commit 8ed08f701d
2 changed files with 22 additions and 19 deletions

View File

@@ -1184,33 +1184,31 @@ pub fn create_or_lookup_by_contact_id(
let contact = Contact::load_from_db(context, contact_id)?; let contact = Contact::load_from_db(context, contact_id)?;
let chat_name = contact.get_display_name(); let chat_name = contact.get_display_name();
sql::execute( context
context, .sql
&context.sql, .start_stmt("create_or_lookup_by_contact_id transaction");
"INSERT INTO chats (type, name, param, blocked, grpid, created_timestamp) VALUES(?, ?, ?, ?, ?, ?)", context.sql.with_conn(|conn| {
let tx = conn.transaction()?;
tx.execute(
"INSERT INTO chats (type, name, param, blocked, created_timestamp) VALUES(?, ?, ?, ?, ?)",
params![ params![
100, Chattype::Single,
chat_name, chat_name,
match contact_id { match contact_id {
DC_CONTACT_ID_SELF => "K=1".to_string(), // K = Param::Selftalk DC_CONTACT_ID_SELF => "K=1".to_string(), // K = Param::Selftalk
DC_CONTACT_ID_DEVICE => "D=1".to_string(), // D = Param::Devicetalk DC_CONTACT_ID_DEVICE => "D=1".to_string(), // D = Param::Devicetalk
_ => "".to_string() _ => "".to_string(),
}, },
create_blocked as u8, create_blocked as u8,
contact.get_addr(),
time(), time(),
] ]
)?; )?;
tx.execute(
let row_id = sql::get_rowid(context, &context.sql, "chats", "grpid", contact.get_addr()); "INSERT INTO chats_contacts (chat_id, contact_id) VALUES((SELECT last_insert_rowid()), ?)",
let chat_id = ChatId::new(row_id); params![contact_id])?;
tx.commit()?;
sql::execute( Ok(())
context, })?;
&context.sql,
"INSERT INTO chats_contacts (chat_id, contact_id) VALUES(?, ?)",
params![chat_id, contact_id],
)?;
if contact_id == DC_CONTACT_ID_SELF { if contact_id == DC_CONTACT_ID_SELF {
update_saved_messages_icon(context)?; update_saved_messages_icon(context)?;
@@ -1218,7 +1216,7 @@ pub fn create_or_lookup_by_contact_id(
update_device_icon(context)?; update_device_icon(context)?;
} }
Ok((chat_id, create_blocked)) lookup_by_contact_id(context, contact_id)
} }
pub fn lookup_by_contact_id( pub fn lookup_by_contact_id(

View File

@@ -893,6 +893,11 @@ fn open(
)?; )?;
sql.set_raw_config_int(context, "dbversion", 62)?; sql.set_raw_config_int(context, "dbversion", 62)?;
} }
if dbversion < 63 {
info!(context, "[migration] v63");
sql.execute("UPDATE chats SET grpid='' WHERE type=100", NO_PARAMS)?;
sql.set_raw_config_int(context, "dbversion", 63)?;
}
// (2) updates that require high-level objects // (2) updates that require high-level objects
// (the structure is complete now and all objects are usable) // (the structure is complete now and all objects are usable)