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, chat_id: uint32_t,
query: *const libc::c_char, query: *const libc::c_char,
) -> *mut dc_array_t { ) -> *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) }; let ret = unsafe { dc_array_new(100 as size_t) };
if !(ret.is_null() || query.is_null()) { let success = context
let real_query = to_string(query).trim().to_string(); .sql
if real_query.is_empty() { .query_map(
success = true; query,
} else { params![chat_id as libc::c_int, &strLikeInText, &strLikeBeg],
let strLikeInText = format!("%{}%", &real_query); |row| row.get::<_, i32>(0),
let strLikeBeg = format!("{}%", &real_query); |rows| {
for id in rows {
let rows = if 0 != chat_id { unsafe { dc_array_add_id(ret, id? as u32) };
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) };
} }
success = true; Ok(())
} },
} )
} .is_ok();
if success { if success {
ret return ret;
} else {
if !ret.is_null() {
unsafe { dc_array_unref(ret) };
}
0 as *mut dc_array_t
} }
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 { 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 { let success = if query_contact_id != 0 {
if let Some(mut stmt) = dc_sqlite3_prepare( (*chatlist).context.sql.query_map(
(*chatlist).context,
&(*chatlist).context.sql,
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \ "SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
ON c.id=m.chat_id \ ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \ 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 (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=?) \ 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;", GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
) { params![query_contact_id as i32],
stmt.query_map(params![query_contact_id as i32], process_fn) process_fn,
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()) |res| res.collect::<rusqlite::Result<Vec<_>>>(),
.is_ok() )
} else {
false
}
} else if 0 != listflags & 0x1 { } else if 0 != listflags & 0x1 {
if let Some(mut stmt) = dc_sqlite3_prepare( (*chatlist).context.sql.query_map(
(*chatlist).context,
&(*chatlist).context.sql,
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \ "SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
ON c.id=m.chat_id \ ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \ 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 (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.archived=1 GROUP BY c.id \ AND c.blocked=0 AND c.archived=1 GROUP BY c.id \
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;", ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
) { params![],
stmt.query_map(params![], process_fn) process_fn,
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()) |res| res.collect::<rusqlite::Result<Vec<_>>>(),
.is_ok() )
} else {
false
}
} else if query__.is_null() { } else if query__.is_null() {
if 0 == listflags & 0x2 { if 0 == listflags & 0x2 {
let last_deaddrop_fresh_msg_id = get_last_deaddrop_fresh_msg((*chatlist).context); 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; add_archived_link_item = 1;
} }
if let Some(mut stmt) = dc_sqlite3_prepare( (*chatlist).context.sql.query_map(
(*chatlist).context,
&(*chatlist).context.sql,
"SELECT c.id, m.id FROM chats c \ "SELECT c.id, m.id FROM chats c \
LEFT JOIN msgs m \ LEFT JOIN msgs m \
ON c.id=m.chat_id \ 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 \ AND c.blocked=0 AND c.archived=0 \
GROUP BY c.id \ GROUP BY c.id \
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;", ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
) { params![],
stmt.query_map(params![], process_fn) process_fn,
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()) |res| res.collect::<rusqlite::Result<Vec<_>>>(),
.is_ok() )
} else {
false
}
} else { } else {
let query = to_string(query__).trim().to_string(); let query = to_string(query__).trim().to_string();
if query.is_empty() { if query.is_empty() {
return 1; return 1;
} else { } else {
let strLikeCmd = format!("%{}%", query); let strLikeCmd = format!("%{}%", query);
if let Some(mut stmt) = dc_sqlite3_prepare( (*chatlist).context.sql.query_map(
(*chatlist).context,
&(*chatlist).context.sql,
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \ "SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
ON c.id=m.chat_id \ ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \ 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 (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.name LIKE ? \ AND c.blocked=0 AND c.name LIKE ? \
GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;", GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
) { params![strLikeCmd],
stmt.query_map(params![strLikeCmd], process_fn) process_fn,
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()) |res| res.collect::<rusqlite::Result<Vec<_>>>(),
.is_ok() )
} else {
false
}
} }
}; };
@@ -248,7 +228,7 @@ unsafe fn dc_chatlist_load_from_db(
} }
(*chatlist).cnt = dc_array_get_cnt((*chatlist).chatNlastmsg_ids).wrapping_div(2); (*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 // 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) Ok(job)
}; };
let jobs = if probe_network == 0 { let query = if probe_network == 0 {
if let Some(mut stmt) = dc_sqlite3_prepare( "SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \
context, FROM jobs WHERE thread=? AND desired_timestamp<=? ORDER BY action DESC, added_timestamp;"
&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
}
} else { } else {
if let Some(mut stmt) = dc_sqlite3_prepare( "SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \
context, FROM jobs WHERE thread=? AND tries>0 ORDER BY desired_timestamp, action DESC;"
&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
}
}; };
if jobs.is_none() { let params_no_probe = params![thread as i64, time()];
return; 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() { context
info!( .sql
context, .query_map(query, params, process_row, |jobs| {
0, for job in jobs {
"{}-job #{}, action {} started...", let mut job: dc_job_t = job?;
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!( info!(
context, context,
0, 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).", "{}-job #{} not succeeded on try #{}, retry in ADD_TIME+{} (in {} seconds).",
if thread == 100 { "INBOX" } else { "SMTP" }, if thread == 100 { "INBOX" } else { "SMTP" },
job.job_id as libc::c_int, 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, time_offset,
job.added_timestamp + time_offset - time() job.added_timestamp + time_offset - time()
); );
if thread == 5000 && tries < 17 - 1 { if thread == 5000 && tries < 17 - 1 {
context context
.smtp_state .smtp_state
.clone() .clone()
.0 .0
.lock() .lock()
.unwrap() .unwrap()
.perform_jobs_needed = 2; .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 { dc_param_unref(job.param);
if job.action == 5901 { free(job.pending_error as *mut libc::c_void);
dc_set_msg_failed(context, job.foreign_id, job.pending_error);
}
dc_job_delete(context, &mut job);
} }
if 0 == probe_network {
continue; Ok(())
} })
// on dc_maybe_network() we stop trying here; .unwrap(); // TODO: better error handling
// 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);
}
} }
fn dc_job_delete(context: &Context, job: &dc_job_t) -> bool { 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 { 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=?;") context
.and_then(|mut stmt| stmt.exists(params![action]).ok()) .sql
.exists("SELECT id FROM jobs WHERE action=?;", params![action])
.unwrap_or_default() .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, dc_strdup((*factory).from_addr) as *mut libc::c_void,
); );
} else { } else {
let rows = if let Some(mut stmt) = dc_sqlite3_prepare( context
context, .sql
&context.sql, .query_map(
"SELECT c.authname, c.addr \ "SELECT c.authname, c.addr \
FROM chats_contacts cc \ FROM chats_contacts cc \
LEFT JOIN contacts c ON cc.contact_id=c.id \ LEFT JOIN contacts c ON cc.contact_id=c.id \
WHERE cc.chat_id=? AND cc.contact_id>9;", WHERE cc.chat_id=? AND cc.contact_id>9;",
) { params![(*(*factory).msg).chat_id as i32],
stmt.query_map(params![(*(*factory).msg).chat_id as i32], |row| { |row| {
let authname: String = row.get(0)?; let authname: String = row.get(0)?;
let addr: String = row.get(1)?; let addr: String = row.get(1)?;
Ok((authname, addr)) Ok((authname, addr))
}) },
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()) |rows| {
.ok() for row in rows {
} else { let (authname, addr) = row?;
None let addr_c = to_cstring(addr);
}; if clist_search_string_nocase(
(*factory).recipients_addr,
if let Some(rows) = rows { addr_c.as_ptr(),
for (authname, addr) in rows { ) == 0
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,
clist_insert_after( (*(*factory).recipients_names).last,
(*factory).recipients_names, if !authname.is_empty() {
(*(*factory).recipients_names).last, dc_strdup(to_cstring(authname).as_ptr())
if !authname.is_empty() { } else {
dc_strdup(to_cstring(authname).as_ptr()) 0 as *mut libc::c_char
} else { } as *mut libc::c_void,
0 as *mut libc::c_char );
} as *mut libc::c_void, clist_insert_after(
); (*factory).recipients_addr,
clist_insert_after( (*(*factory).recipients_addr).last,
(*factory).recipients_addr, dc_strdup(addr_c.as_ptr()) as *mut libc::c_void,
(*(*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); let command = dc_param_get_int((*(*factory).msg).param, 'S' as i32, 0);
if command == 5 { if command == 5 {
@@ -219,21 +220,17 @@ pub unsafe fn dc_mimefactory_load_msg(
} }
} }
let row = dc_sqlite3_prepare( let row = context.sql.query_row(
context,
&context.sql,
"SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?", "SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?",
) params![(*(*factory).msg).id as i32],
.and_then(|mut stmt| { |row| {
stmt.query_row(params![(*(*factory).msg).id as i32], |row| {
let in_reply_to: String = row.get(0)?; let in_reply_to: String = row.get(0)?;
let references: String = row.get(1)?; let references: String = row.get(1)?;
Ok((in_reply_to, references)) Ok((in_reply_to, references))
}) },
.ok() );
}); if let Ok((in_reply_to, references)) = row {
if let Some((in_reply_to, references)) = row {
(*factory).in_reply_to = dc_strdup(to_cstring(in_reply_to).as_ptr()); (*factory).in_reply_to = dc_strdup(to_cstring(in_reply_to).as_ptr());
(*factory).references = dc_strdup(to_cstring(references).as_ptr()); (*factory).references = dc_strdup(to_cstring(references).as_ptr());
} }

View File

@@ -59,6 +59,9 @@ impl SQLite {
self.connection.read().unwrap() 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>( pub fn query_map<T, P, F, G, H>(
&self, &self,
sql: &str, sql: &str,
@@ -80,6 +83,21 @@ impl SQLite {
g(res) 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> pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> rusqlite::Result<T>
where where
P: IntoIterator, P: IntoIterator,