less preparation

This commit is contained in:
dignifiedquire
2019-07-06 18:12:27 +02:00
parent 8790a2dc52
commit 180bc926b6
5 changed files with 270 additions and 285 deletions

View File

@@ -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::<rusqlite::Result<Vec<i32>>>()).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::<rusqlite::Result<Vec<i32>>>()).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<str>) -> bool {

View File

@@ -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::<rusqlite::Result<Vec<_>>>())
.is_ok()
} else {
false
}
params![query_contact_id as i32],
process_fn,
|res| res.collect::<rusqlite::Result<Vec<_>>>(),
)
} 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::<rusqlite::Result<Vec<_>>>())
.is_ok()
} else {
false
}
params![],
process_fn,
|res| res.collect::<rusqlite::Result<Vec<_>>>(),
)
} 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::<rusqlite::Result<Vec<_>>>())
.is_ok()
} else {
false
}
params![],
process_fn,
|res| res.collect::<rusqlite::Result<Vec<_>>>(),
)
} 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::<rusqlite::Result<Vec<_>>>())
.is_ok()
} else {
false
}
params![strLikeCmd],
process_fn,
|res| res.collect::<rusqlite::Result<Vec<_>>>(),
)
}
};
@@ -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

View File

@@ -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::<rusqlite::Result<Vec<_>>>()).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::<rusqlite::Result<Vec<_>>>())
.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()
}

View File

@@ -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::<rusqlite::Result<Vec<_>>>())
.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());
}

View File

@@ -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<T, P, F, G, H>(
&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<P>(&self, sql: &str, params: P) -> rusqlite::Result<bool>
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<T, P, F>(&self, sql: &str, params: P, f: F) -> rusqlite::Result<T>
where
P: IntoIterator,