diff --git a/src/chat.rs b/src/chat.rs index 052f81596..8878dc6ea 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -958,7 +958,6 @@ impl Chat { timestamp: i64, ) -> Result { let mut new_references = "".into(); - let mut msg_id = 0; let mut to_id = 0; let mut location_id = 0; @@ -1066,10 +1065,10 @@ impl Chat { // add independent location to database - if msg.param.exists(Param::SetLatitude) - && context + if msg.param.exists(Param::SetLatitude) { + if let Ok(row_id) = context .sql - .execute( + .insert( sqlx::query( "INSERT INTO locations \ (timestamp,from_id,chat_id, latitude,longitude,independent)\ @@ -1082,18 +1081,9 @@ impl Chat { .bind(msg.param.get_float(Param::SetLongitude).unwrap_or_default()), ) .await - .is_ok() - { - location_id = context - .sql - .get_rowid2( - "locations", - "timestamp", - timestamp, - "from_id", - DC_CONTACT_ID_SELF as i64, - ) - .await?; + { + location_id = row_id; + } } let ephemeral_timer = if msg.param.get_cmd() == SystemMessage::EphemeralTimerChanged { @@ -1123,9 +1113,9 @@ impl Chat { // add message to the database - if context + let msg_id = context .sql - .execute( + .insert( sqlx::query( "INSERT INTO msgs ( rfc724_mid, @@ -1168,19 +1158,7 @@ impl Chat { .bind(ephemeral_timer) .bind(ephemeral_timestamp), ) - .await - .is_ok() - { - msg_id = context - .sql - .get_rowid("msgs", "rfc724_mid", new_rfc724_mid) - .await?; - } else { - error!( - context, - "Cannot send message, cannot insert to database ({}).", self.id, - ); - } + .await?; schedule_ephemeral_task(context).await; Ok(MsgId::new(u32::try_from(msg_id)?)) @@ -2173,9 +2151,9 @@ pub async fn create_group_chat( let draft_txt = stock_str::new_group_draft(context, &chat_name).await; let grpid = dc_create_id(); - context + let row_id = context .sql - .execute( + .insert( sqlx::query( "INSERT INTO chats (type, name, grpid, param, created_timestamp) @@ -2188,8 +2166,6 @@ pub async fn create_group_chat( ) .await?; - let row_id = context.sql.get_rowid("chats", "grpid", grpid).await?; - let chat_id = ChatId::new(u32::try_from(row_id)?); if add_to_chat_contacts_table(context, chat_id, DC_CONTACT_ID_SELF).await { let mut draft_msg = Message::new(Viewtype::Text); @@ -2945,9 +2921,9 @@ pub async fn add_device_msg_with_importance( } } - context + let row_id = context .sql - .execute( + .insert( sqlx::query( "INSERT INTO msgs ( chat_id, @@ -2979,10 +2955,6 @@ pub async fn add_device_msg_with_importance( ) .await?; - let row_id = context - .sql - .get_rowid("msgs", "rfc724_mid", &rfc724_mid) - .await?; msg_id = MsgId::new(u32::try_from(row_id)?); } @@ -3056,7 +3028,8 @@ pub(crate) async fn add_info_msg_with_cmd( param.set_cmd(cmd) } - context.sql.execute( + let row_id = + context.sql.insert( sqlx::query("INSERT INTO msgs (chat_id,from_id,to_id, timestamp,type,state, txt,rfc724_mid,ephemeral_timer, param) VALUES (?,?,?, ?,?,?, ?,?,?, ?);") .bind(chat_id) .bind(DC_CONTACT_ID_INFO as i32) @@ -3070,11 +3043,6 @@ pub(crate) async fn add_info_msg_with_cmd( .bind(param.to_string()) ).await?; - let row_id = context - .sql - .get_rowid("msgs", "rfc724_mid", &rfc724_mid) - .await - .unwrap_or_default(); let msg_id = MsgId::new(u32::try_from(row_id)?); context.emit_event(EventType::MsgsChanged { chat_id, msg_id }); Ok(msg_id) diff --git a/src/contact.rs b/src/contact.rs index 2f9cf9241..d27f231f9 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -530,9 +530,9 @@ impl Contact { let update_name = manual; let update_authname = !manual; - if context + if let Ok(new_row_id) = context .sql - .execute( + .insert( sqlx::query( "INSERT INTO contacts (name, addr, origin, authname) VALUES(?, ?, ?, ?);", ) @@ -550,9 +550,8 @@ impl Contact { }), ) .await - .is_ok() { - row_id = context.sql.get_rowid("contacts", "addr", &addr).await?; + row_id = new_row_id; sth_modified = Modifier::Created; info!(context, "added contact id={} addr={}", row_id, &addr); } else { diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 9e1145059..98a5f9fb4 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -978,9 +978,9 @@ async fn add_parts( // also change `MsgId::trash()` and `delete_expired_messages()` let trash = chat_id.is_trash(); - context + let row_id = context .sql - .execute( + .insert( sqlx::query( r#" INSERT INTO msgs @@ -1040,12 +1040,7 @@ INSERT INTO msgs .bind(ephemeral_timestamp), ) .await?; - let msg_id = MsgId::new(u32::try_from( - context - .sql - .get_rowid("msgs", "rfc724_mid", &rfc724_mid) - .await?, - )?); + let msg_id = MsgId::new(u32::try_from(row_id)?); created_db_entries.push((*chat_id, msg_id)); *insert_msg_id = msg_id; @@ -1769,7 +1764,8 @@ async fn create_multiuser_record( create_blocked: Blocked, create_protected: ProtectionStatus, ) -> Result { - context.sql.execute( + let row_id = + context.sql.insert( sqlx::query( "INSERT INTO chats (type, name, grpid, blocked, created_timestamp, protected) VALUES(?, ?, ?, ?, ?, ?);") .bind(chattype) @@ -1780,11 +1776,6 @@ async fn create_multiuser_record( .bind(create_protected) ).await?; - let row_id = context - .sql - .get_rowid("chats", "grpid", grpid.as_ref()) - .await?; - let chat_id = ChatId::new(u32::try_from(row_id)?); info!( context, diff --git a/src/location.rs b/src/location.rs index 3671339ca..caa941f5d 100644 --- a/src/location.rs +++ b/src/location.rs @@ -571,9 +571,9 @@ pub async fn save( .exists(sqlx::query(stmt_test).bind(timestamp).bind(contact_id)) .await?; if independent || !exists { - context + let row_id = context .sql - .execute( + .insert( sqlx::query(stmt_insert) .bind(timestamp) .bind(contact_id) @@ -587,16 +587,7 @@ pub async fn save( if timestamp > newest_timestamp { newest_timestamp = timestamp; - newest_location_id = context - .sql - .get_rowid2( - "locations", - "timestamp", - timestamp, - "from_id", - contact_id as i64, - ) - .await?; + newest_location_id = row_id; } } } diff --git a/src/message.rs b/src/message.rs index 9b971e977..75e1e72ff 100644 --- a/src/message.rs +++ b/src/message.rs @@ -317,7 +317,8 @@ impl Message { pub async fn load_from_db(context: &Context, id: MsgId) -> Result { ensure!( !id.is_special(), - "Can not load special message IDs from DB." + "Can not load special message ID {} from DB.", + id ); let row = context .sql diff --git a/src/sql/mod.rs b/src/sql/mod.rs index 93a79ab51..cc05933ad 100644 --- a/src/sql/mod.rs +++ b/src/sql/mod.rs @@ -222,6 +222,18 @@ PRAGMA query_only=1; -- Protect against writes even in read-write mode Ok(rows.rows_affected()) } + /// Executes the given query, returning the last inserted row ID. + pub async fn insert<'q, E>(&self, query: Query<'q, Sqlite, E>) -> Result + where + E: 'q + IntoArguments<'q, Sqlite>, + { + let lock = self.writer.read().await; + let pool = lock.as_ref().ok_or(Error::SqlNoConnection)?; + + let rows = pool.execute(query).await?; + Ok(rows.last_insert_rowid()) + } + /// Execute many queries. pub async fn execute_many<'q, E>(&self, query: Query<'q, Sqlite, E>) -> Result<()> where @@ -484,52 +496,6 @@ PRAGMA query_only=1; -- Protect against writes even in read-write mode .await .map(|s| s.and_then(|r| r.parse().ok())) } - - /// Alternative to sqlite3_last_insert_rowid() which MUST NOT be used due to race conditions, see comment above. - /// the ORDER BY ensures, this function always returns the most recent id, - /// eg. if a Message-ID is split into different messages. - pub async fn get_rowid( - &self, - table: impl AsRef, - field: impl AsRef, - value: impl AsRef, - ) -> Result { - // alternative to sqlite3_last_insert_rowid() which MUST NOT be used due to race conditions, see comment above. - // the ORDER BY ensures, this function always returns the most recent id, - // eg. if a Message-ID is split into different messages. - let query = format!( - "SELECT id FROM {} WHERE {}=? ORDER BY id DESC", - table.as_ref(), - field.as_ref(), - ); - - self.query_get_value(sqlx::query(&query).bind(value.as_ref())) - .await - .map(|id| id.unwrap_or_default()) - } - - /// Fetches the rowid by restricting the rows through two different key, value settings. - pub async fn get_rowid2( - &self, - table: impl AsRef, - field: impl AsRef, - value: i64, - field2: impl AsRef, - value2: i64, - ) -> Result { - let query = format!( - "SELECT id FROM {} WHERE {}={} AND {}={} ORDER BY id DESC", - table.as_ref(), - field.as_ref(), - value, - field2.as_ref(), - value2, - ); - - self.query_get_value(sqlx::query(&query)) - .await - .map(|id| id.unwrap_or_default()) - } } pub async fn housekeeping(context: &Context) -> Result<()> {