From 180bc926b65f78d09111c61ce24397f11efa414b Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Sat, 6 Jul 2019 18:12:27 +0200 Subject: [PATCH] less preparation --- src/context.rs | 90 ++++++------- src/dc_chatlist.rs | 62 ++++----- src/dc_job.rs | 286 +++++++++++++++++++++--------------------- src/dc_mimefactory.rs | 99 +++++++-------- src/dc_sqlite3.rs | 18 +++ 5 files changed, 270 insertions(+), 285 deletions(-) diff --git a/src/context.rs b/src/context.rs index 7942ed74c..98d37af4d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -700,61 +700,53 @@ pub fn dc_search_msgs( chat_id: uint32_t, query: *const libc::c_char, ) -> *mut dc_array_t { - let mut success = false; + if query.is_null() { + return std::ptr::null_mut(); + } + + let real_query = to_string(query).trim().to_string(); + if real_query.is_empty() { + return std::ptr::null_mut(); + } + let strLikeInText = format!("%{}%", &real_query); + let strLikeBeg = format!("{}%", &real_query); + + let query = if 0 != chat_id { + "SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id WHERE m.chat_id=? \ + AND m.hidden=0 \ + AND ct.blocked=0 AND (txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp,m.id;" + } else { + "SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id \ + LEFT JOIN chats c ON m.chat_id=c.id WHERE m.chat_id>9 AND m.hidden=0 \ + AND (c.blocked=0 OR c.blocked=?) \ + AND ct.blocked=0 AND (m.txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp DESC,m.id DESC;" + }; + let ret = unsafe { dc_array_new(100 as size_t) }; - if !(ret.is_null() || query.is_null()) { - let real_query = to_string(query).trim().to_string(); - if real_query.is_empty() { - success = true; - } else { - let strLikeInText = format!("%{}%", &real_query); - let strLikeBeg = format!("{}%", &real_query); - - let rows = if 0 != chat_id { - dc_sqlite3_prepare( - context, - &context.sql, - "SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id WHERE m.chat_id=? \ - AND m.hidden=0 \ - AND ct.blocked=0 AND (txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp,m.id;" - ).and_then(|mut stmt| stmt.query_map( - params![chat_id as libc::c_int, &strLikeInText, &strLikeBeg], - |row| row.get::<_, i32>(0) - ).and_then(|res| res.collect::>>()).ok()) - } else { - let show_deaddrop = 0; - dc_sqlite3_prepare( - context, - &context.sql, - "SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id \ - LEFT JOIN chats c ON m.chat_id=c.id WHERE m.chat_id>9 AND m.hidden=0 \ - AND (c.blocked=0 OR c.blocked=?) \ - AND ct.blocked=0 AND (m.txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp DESC,m.id DESC;" - ).and_then(|mut stmt| - stmt.query_map(params![ - if 0 != show_deaddrop { 2 } else { 0 }, - strLikeInText, strLikeBeg, - ], |row| row.get::<_, i32>(0)).and_then(|res| res.collect::>>()).ok() - ) - }; - if let Some(ids) = rows { - for id in ids { - unsafe { dc_array_add_id(ret, id as u32) }; + let success = context + .sql + .query_map( + query, + params![chat_id as libc::c_int, &strLikeInText, &strLikeBeg], + |row| row.get::<_, i32>(0), + |rows| { + for id in rows { + unsafe { dc_array_add_id(ret, id? as u32) }; } - success = true; - } - } - } + Ok(()) + }, + ) + .is_ok(); if success { - ret - } else { - if !ret.is_null() { - unsafe { dc_array_unref(ret) }; - } - 0 as *mut dc_array_t + return ret; } + + if !ret.is_null() { + unsafe { dc_array_unref(ret) }; + } + std::ptr::null_mut() } pub fn dc_is_inbox(_context: &Context, folder_name: impl AsRef) -> bool { diff --git a/src/dc_chatlist.rs b/src/dc_chatlist.rs index 15ce6c1db..a029c5328 100644 --- a/src/dc_chatlist.rs +++ b/src/dc_chatlist.rs @@ -149,9 +149,7 @@ unsafe fn dc_chatlist_load_from_db( }; let success = if query_contact_id != 0 { - if let Some(mut stmt) = dc_sqlite3_prepare( - (*chatlist).context, - &(*chatlist).context.sql, + (*chatlist).context.sql.query_map( "SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \ ON c.id=m.chat_id \ AND m.timestamp=( SELECT MAX(timestamp) \ @@ -159,17 +157,12 @@ unsafe fn dc_chatlist_load_from_db( AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \ AND c.blocked=0 AND c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?) \ GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;", - ) { - stmt.query_map(params![query_contact_id as i32], process_fn) - .and_then(|res| res.collect::>>()) - .is_ok() - } else { - false - } + params![query_contact_id as i32], + process_fn, + |res| res.collect::>>(), + ) } else if 0 != listflags & 0x1 { - if let Some(mut stmt) = dc_sqlite3_prepare( - (*chatlist).context, - &(*chatlist).context.sql, + (*chatlist).context.sql.query_map( "SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \ ON c.id=m.chat_id \ AND m.timestamp=( SELECT MAX(timestamp) \ @@ -177,13 +170,10 @@ unsafe fn dc_chatlist_load_from_db( AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \ AND c.blocked=0 AND c.archived=1 GROUP BY c.id \ ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;", - ) { - stmt.query_map(params![], process_fn) - .and_then(|res| res.collect::>>()) - .is_ok() - } else { - false - } + params![], + process_fn, + |res| res.collect::>>(), + ) } else if query__.is_null() { if 0 == listflags & 0x2 { let last_deaddrop_fresh_msg_id = get_last_deaddrop_fresh_msg((*chatlist).context); @@ -193,9 +183,7 @@ unsafe fn dc_chatlist_load_from_db( } add_archived_link_item = 1; } - if let Some(mut stmt) = dc_sqlite3_prepare( - (*chatlist).context, - &(*chatlist).context.sql, + (*chatlist).context.sql.query_map( "SELECT c.id, m.id FROM chats c \ LEFT JOIN msgs m \ ON c.id=m.chat_id \ @@ -205,22 +193,17 @@ unsafe fn dc_chatlist_load_from_db( AND c.blocked=0 AND c.archived=0 \ GROUP BY c.id \ ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;", - ) { - stmt.query_map(params![], process_fn) - .and_then(|res| res.collect::>>()) - .is_ok() - } else { - false - } + params![], + process_fn, + |res| res.collect::>>(), + ) } else { let query = to_string(query__).trim().to_string(); if query.is_empty() { return 1; } else { let strLikeCmd = format!("%{}%", query); - if let Some(mut stmt) = dc_sqlite3_prepare( - (*chatlist).context, - &(*chatlist).context.sql, + (*chatlist).context.sql.query_map( "SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \ ON c.id=m.chat_id \ AND m.timestamp=( SELECT MAX(timestamp) \ @@ -228,13 +211,10 @@ unsafe fn dc_chatlist_load_from_db( AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \ AND c.blocked=0 AND c.name LIKE ? \ GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;", - ) { - stmt.query_map(params![strLikeCmd], process_fn) - .and_then(|res| res.collect::>>()) - .is_ok() - } else { - false - } + params![strLikeCmd], + process_fn, + |res| res.collect::>>(), + ) } }; @@ -248,7 +228,7 @@ unsafe fn dc_chatlist_load_from_db( } (*chatlist).cnt = dc_array_get_cnt((*chatlist).chatNlastmsg_ids).wrapping_div(2); - success as libc::c_int + success.is_ok() as libc::c_int } // Context functions to work with chatlist diff --git a/src/dc_job.rs b/src/dc_job.rs index ab7dad5dc..cfc5551d2 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -85,128 +85,121 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: Ok(job) }; - let jobs = if probe_network == 0 { - if let Some(mut stmt) = dc_sqlite3_prepare( - context, - &context.sql, - "SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \ - FROM jobs WHERE thread=? AND desired_timestamp<=? ORDER BY action DESC, added_timestamp;" - ) { - stmt.query_map(params![thread as i64, time()], process_row) - .and_then(|res| res.collect::>>()).ok() - } else { - None - } + let query = if probe_network == 0 { + "SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \ + FROM jobs WHERE thread=? AND desired_timestamp<=? ORDER BY action DESC, added_timestamp;" } else { - if let Some(mut stmt) = dc_sqlite3_prepare( - context, - &context.sql, - "SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \ - FROM jobs WHERE thread=? AND tries>0 ORDER BY desired_timestamp, action DESC;", - ) { - stmt.query_map(params![thread as i64], process_row) - .and_then(|res| res.collect::>>()) - .ok() - } else { - None - } + "SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \ + FROM jobs WHERE thread=? AND tries>0 ORDER BY desired_timestamp, action DESC;" }; - if jobs.is_none() { - return; - } + let params_no_probe = params![thread as i64, time()]; + let params_probe = params![thread as i64]; + let params: &[&dyn rusqlite::ToSql] = if probe_network == 0 { + params_no_probe + } else { + params_probe + }; - for mut job in jobs.unwrap() { - info!( - context, - 0, - "{}-job #{}, action {} started...", - if thread == 100 { "INBOX" } else { "SMTP" }, - job.job_id, - job.action, - ); - - if 900 == job.action || 910 == job.action { - dc_job_kill_action(context, job.action); - dc_jobthread_suspend(context, &context.sentbox_thread.clone().read().unwrap(), 1); - dc_jobthread_suspend(context, &context.mvbox_thread.clone().read().unwrap(), 1); - dc_suspend_smtp_thread(context, 1); - } - let mut tries = 0; - while tries <= 1 { - job.try_again = 0; - match job.action { - 5901 => { - dc_job_do_DC_JOB_SEND(context, &mut job); - } - 110 => { - dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(context, &mut job); - } - 130 => { - dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context, &mut job); - } - 120 => { - dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context, &mut job); - } - 200 => { - dc_job_do_DC_JOB_MOVE_MSG(context, &mut job); - } - 5011 => { - dc_job_do_DC_JOB_SEND(context, &mut job); - } - 900 => { - dc_job_do_DC_JOB_CONFIGURE_IMAP(context, &mut job); - } - 910 => { - dc_job_do_DC_JOB_IMEX_IMAP(context, &mut job); - } - 5005 => { - dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context, &mut job); - } - 5007 => { - dc_job_do_DC_JOB_MAYBE_SEND_LOC_ENDED(context, &mut job); - } - 105 => { - dc_housekeeping(context); - } - _ => {} - } - if job.try_again != -1 { - break; - } - tries += 1 - } - if 900 == job.action || 910 == job.action { - dc_jobthread_suspend( - context, - &mut context.sentbox_thread.clone().read().unwrap(), - 0, - ); - dc_jobthread_suspend( - context, - &mut context.mvbox_thread.clone().read().unwrap(), - 0, - ); - dc_suspend_smtp_thread(context, 0); - break; - } else if job.try_again == 2 { - info!( - context, - 0, - "{}-job #{} not yet ready and will be delayed.", - if thread == 100 { "INBOX" } else { "SMTP" }, - job.job_id - ); - } else if job.try_again == -1 || job.try_again == 3 { - let tries = job.tries + 1; - if tries < 17 { - job.tries = tries; - let time_offset = get_backoff_time_offset(tries); - job.desired_timestamp = job.added_timestamp + time_offset; - dc_job_update(context, &mut job); + context + .sql + .query_map(query, params, process_row, |jobs| { + for job in jobs { + let mut job: dc_job_t = job?; info!( context, 0, + "{}-job #{}, action {} started...", + if thread == 100 { "INBOX" } else { "SMTP" }, + job.job_id, + job.action, + ); + + if 900 == job.action || 910 == job.action { + dc_job_kill_action(context, job.action); + dc_jobthread_suspend( + context, + &context.sentbox_thread.clone().read().unwrap(), + 1, + ); + dc_jobthread_suspend(context, &context.mvbox_thread.clone().read().unwrap(), 1); + dc_suspend_smtp_thread(context, 1); + } + let mut tries = 0; + while tries <= 1 { + job.try_again = 0; + match job.action { + 5901 => { + dc_job_do_DC_JOB_SEND(context, &mut job); + } + 110 => { + dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(context, &mut job); + } + 130 => { + dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context, &mut job); + } + 120 => { + dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context, &mut job); + } + 200 => { + dc_job_do_DC_JOB_MOVE_MSG(context, &mut job); + } + 5011 => { + dc_job_do_DC_JOB_SEND(context, &mut job); + } + 900 => { + dc_job_do_DC_JOB_CONFIGURE_IMAP(context, &mut job); + } + 910 => { + dc_job_do_DC_JOB_IMEX_IMAP(context, &mut job); + } + 5005 => { + dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context, &mut job); + } + 5007 => { + dc_job_do_DC_JOB_MAYBE_SEND_LOC_ENDED(context, &mut job); + } + 105 => { + dc_housekeeping(context); + } + _ => {} + } + if job.try_again != -1 { + break; + } + tries += 1 + } + if 900 == job.action || 910 == job.action { + dc_jobthread_suspend( + context, + &mut context.sentbox_thread.clone().read().unwrap(), + 0, + ); + dc_jobthread_suspend( + context, + &mut context.mvbox_thread.clone().read().unwrap(), + 0, + ); + dc_suspend_smtp_thread(context, 0); + break; + } else if job.try_again == 2 { + info!( + context, + 0, + "{}-job #{} not yet ready and will be delayed.", + if thread == 100 { "INBOX" } else { "SMTP" }, + job.job_id + ); + } else if job.try_again == -1 || job.try_again == 3 { + let tries = job.tries + 1; + if tries < 17 { + job.tries = tries; + let time_offset = get_backoff_time_offset(tries); + job.desired_timestamp = job.added_timestamp + time_offset; + dc_job_update(context, &mut job); + info!( + context, + 0, "{}-job #{} not succeeded on try #{}, retry in ADD_TIME+{} (in {} seconds).", if thread == 100 { "INBOX" } else { "SMTP" }, job.job_id as libc::c_int, @@ -214,35 +207,39 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: time_offset, job.added_timestamp + time_offset - time() ); - if thread == 5000 && tries < 17 - 1 { - context - .smtp_state - .clone() - .0 - .lock() - .unwrap() - .perform_jobs_needed = 2; + if thread == 5000 && tries < 17 - 1 { + context + .smtp_state + .clone() + .0 + .lock() + .unwrap() + .perform_jobs_needed = 2; + } + } else { + if job.action == 5901 { + dc_set_msg_failed(context, job.foreign_id, job.pending_error); + } + dc_job_delete(context, &mut job); + } + if 0 == probe_network { + continue; + } + // on dc_maybe_network() we stop trying here; + // these jobs are already tried once. + // otherwise, we just continue with the next job + // to give other jobs a chance being tried at least once. + break; + } else { + dc_job_delete(context, &mut job); } - } else { - if job.action == 5901 { - dc_set_msg_failed(context, job.foreign_id, job.pending_error); - } - dc_job_delete(context, &mut job); + dc_param_unref(job.param); + free(job.pending_error as *mut libc::c_void); } - if 0 == probe_network { - continue; - } - // on dc_maybe_network() we stop trying here; - // these jobs are already tried once. - // otherwise, we just continue with the next job - // to give other jobs a chance being tried at least once. - break; - } else { - dc_job_delete(context, &mut job); - } - dc_param_unref(job.param); - free(job.pending_error as *mut libc::c_void); - } + + Ok(()) + }) + .unwrap(); // TODO: better error handling } fn dc_job_delete(context: &Context, job: &dc_job_t) -> bool { @@ -1166,8 +1163,9 @@ pub unsafe fn dc_maybe_network(context: &Context) { } pub fn dc_job_action_exists(context: &Context, action: libc::c_int) -> bool { - dc_sqlite3_prepare(context, &context.sql, "SELECT id FROM jobs WHERE action=?;") - .and_then(|mut stmt| stmt.exists(params![action]).ok()) + context + .sql + .exists("SELECT id FROM jobs WHERE action=?;", params![action]) .unwrap_or_default() } diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index 5bb951b99..d61d11c57 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -140,47 +140,48 @@ pub unsafe fn dc_mimefactory_load_msg( dc_strdup((*factory).from_addr) as *mut libc::c_void, ); } else { - let rows = if let Some(mut stmt) = dc_sqlite3_prepare( - context, - &context.sql, - "SELECT c.authname, c.addr \ - FROM chats_contacts cc \ - LEFT JOIN contacts c ON cc.contact_id=c.id \ - WHERE cc.chat_id=? AND cc.contact_id>9;", - ) { - stmt.query_map(params![(*(*factory).msg).chat_id as i32], |row| { - let authname: String = row.get(0)?; - let addr: String = row.get(1)?; - Ok((authname, addr)) - }) - .and_then(|res| res.collect::>>()) - .ok() - } else { - None - }; - - if let Some(rows) = rows { - for (authname, addr) in rows { - let addr_c = to_cstring(addr); - if clist_search_string_nocase((*factory).recipients_addr, addr_c.as_ptr()) == 0 - { - clist_insert_after( - (*factory).recipients_names, - (*(*factory).recipients_names).last, - if !authname.is_empty() { - dc_strdup(to_cstring(authname).as_ptr()) - } else { - 0 as *mut libc::c_char - } as *mut libc::c_void, - ); - clist_insert_after( - (*factory).recipients_addr, - (*(*factory).recipients_addr).last, - dc_strdup(addr_c.as_ptr()) as *mut libc::c_void, - ); - } - } - } + context + .sql + .query_map( + "SELECT c.authname, c.addr \ + FROM chats_contacts cc \ + LEFT JOIN contacts c ON cc.contact_id=c.id \ + WHERE cc.chat_id=? AND cc.contact_id>9;", + params![(*(*factory).msg).chat_id as i32], + |row| { + let authname: String = row.get(0)?; + let addr: String = row.get(1)?; + Ok((authname, addr)) + }, + |rows| { + for row in rows { + let (authname, addr) = row?; + let addr_c = to_cstring(addr); + if clist_search_string_nocase( + (*factory).recipients_addr, + addr_c.as_ptr(), + ) == 0 + { + clist_insert_after( + (*factory).recipients_names, + (*(*factory).recipients_names).last, + if !authname.is_empty() { + dc_strdup(to_cstring(authname).as_ptr()) + } else { + 0 as *mut libc::c_char + } as *mut libc::c_void, + ); + clist_insert_after( + (*factory).recipients_addr, + (*(*factory).recipients_addr).last, + dc_strdup(addr_c.as_ptr()) as *mut libc::c_void, + ); + } + } + Ok(()) + }, + ) + .unwrap(); let command = dc_param_get_int((*(*factory).msg).param, 'S' as i32, 0); if command == 5 { @@ -219,21 +220,17 @@ pub unsafe fn dc_mimefactory_load_msg( } } - let row = dc_sqlite3_prepare( - context, - &context.sql, + let row = context.sql.query_row( "SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?", - ) - .and_then(|mut stmt| { - stmt.query_row(params![(*(*factory).msg).id as i32], |row| { + params![(*(*factory).msg).id as i32], + |row| { let in_reply_to: String = row.get(0)?; let references: String = row.get(1)?; Ok((in_reply_to, references)) - }) - .ok() - }); - if let Some((in_reply_to, references)) = row { + }, + ); + if let Ok((in_reply_to, references)) = row { (*factory).in_reply_to = dc_strdup(to_cstring(in_reply_to).as_ptr()); (*factory).references = dc_strdup(to_cstring(references).as_ptr()); } diff --git a/src/dc_sqlite3.rs b/src/dc_sqlite3.rs index 704bcfc80..92dadd3eb 100644 --- a/src/dc_sqlite3.rs +++ b/src/dc_sqlite3.rs @@ -59,6 +59,9 @@ impl SQLite { self.connection.read().unwrap() } + /// Prepares and executes the statement and maps a function over the resulting rows. + /// Then executes the second function over the returned iterator and returns the + /// result of that function. pub fn query_map( &self, sql: &str, @@ -80,6 +83,21 @@ impl SQLite { g(res) } + /// Return `true` if a query in the SQL statement it executes returns one or more + /// rows and false if the SQL returns an empty set. + pub fn exists

(&self, sql: &str, params: P) -> rusqlite::Result + where + P: IntoIterator, + P::Item: rusqlite::ToSql, + { + let conn_lock = self.connection.read().unwrap(); + let conn = conn_lock.as_ref().expect("database closed"); + + let mut stmt = conn.prepare(sql)?; + let res = stmt.exists(params)?; + Ok(res) + } + pub fn query_row(&self, sql: &str, params: P, f: F) -> rusqlite::Result where P: IntoIterator,