more improvements in sql code

This commit is contained in:
dignifiedquire
2019-07-07 21:05:47 +02:00
parent 180bc926b6
commit 0ff09e55c7
5 changed files with 240 additions and 248 deletions

View File

@@ -148,8 +148,9 @@ unsafe fn dc_chatlist_load_from_db(
Ok(()) Ok(())
}; };
let success = if query_contact_id != 0 { let success =
(*chatlist).context.sql.query_map( if query_contact_id != 0 {
(*chatlist).context.sql.query_map(
"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,64 +160,73 @@ unsafe fn dc_chatlist_load_from_db(
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], params![query_contact_id as i32],
process_fn, process_fn,
|res| res.collect::<rusqlite::Result<Vec<_>>>(), |res| res.collect::<rusqlite::Result<Vec<_>>>().map_err(Into::into),
) )
} else if 0 != listflags & 0x1 { } else if 0 != listflags & 0x1 {
(*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) \
FROM msgs WHERE chat_id=c.id \
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;",
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);
if last_deaddrop_fresh_msg_id > 0 {
dc_array_add_id((*chatlist).chatNlastmsg_ids, 1);
dc_array_add_id((*chatlist).chatNlastmsg_ids, last_deaddrop_fresh_msg_id);
}
add_archived_link_item = 1;
}
(*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) \
FROM msgs WHERE chat_id=c.id \
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.archived=0 \
GROUP BY c.id \
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
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);
(*chatlist).context.sql.query_map( (*chatlist).context.sql.query_map(
"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) \
FROM msgs WHERE chat_id=c.id \ FROM msgs WHERE chat_id=c.id \
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.archived=1 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![strLikeCmd], params![],
process_fn, process_fn,
|res| res.collect::<rusqlite::Result<Vec<_>>>(), |res| {
res.collect::<rusqlite::Result<Vec<_>>>()
.map_err(Into::into)
},
) )
} } else if query__.is_null() {
}; if 0 == listflags & 0x2 {
let last_deaddrop_fresh_msg_id = get_last_deaddrop_fresh_msg((*chatlist).context);
if last_deaddrop_fresh_msg_id > 0 {
dc_array_add_id((*chatlist).chatNlastmsg_ids, 1);
dc_array_add_id((*chatlist).chatNlastmsg_ids, last_deaddrop_fresh_msg_id);
}
add_archived_link_item = 1;
}
(*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) \
FROM msgs WHERE chat_id=c.id \
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.archived=0 \
GROUP BY c.id \
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![],
process_fn,
|res| {
res.collect::<rusqlite::Result<Vec<_>>>()
.map_err(Into::into)
},
)
} else {
let query = to_string(query__).trim().to_string();
if query.is_empty() {
return 1;
} else {
let strLikeCmd = format!("%{}%", query);
(*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) \
FROM msgs WHERE chat_id=c.id \
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;",
params![strLikeCmd],
process_fn,
|res| {
res.collect::<rusqlite::Result<Vec<_>>>()
.map_err(Into::into)
},
)
}
};
if 0 != add_archived_link_item && dc_get_archived_cnt((*chatlist).context) > 0 { if 0 != add_archived_link_item && dc_get_archived_cnt((*chatlist).context) > 0 {
if dc_array_get_cnt((*chatlist).chatNlastmsg_ids) == 0 && 0 != listflags & 0x4 { if dc_array_get_cnt((*chatlist).chatNlastmsg_ids) == 0 && 0 != listflags & 0x4 {

View File

@@ -1,5 +1,6 @@
use std::ffi::CString; use std::ffi::CString;
use failure::format_err;
use mmime::mailmime_content::*; use mmime::mailmime_content::*;
use mmime::mmapstring::*; use mmime::mmapstring::*;
use mmime::other::*; use mmime::other::*;
@@ -798,11 +799,6 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
// TODO should return bool /rtn // TODO should return bool /rtn
unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char) -> libc::c_int { unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char) -> libc::c_int {
let mut success = 0;
let mut processed_files_cnt = 0;
let total_files_cnt: usize;
info!( info!(
context, context,
0, 0,
@@ -813,49 +809,54 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
if 0 != dc_is_configured(context) { if 0 != dc_is_configured(context) {
error!(context, 0, "Cannot import backups to accounts in use."); error!(context, 0, "Cannot import backups to accounts in use.");
} else { return 0;
&context.sql.close(&context); }
dc_delete_file(context, context.get_dbfile()); &context.sql.close(&context);
if 0 != dc_file_exist(context, context.get_dbfile()) { dc_delete_file(context, context.get_dbfile());
error!( if 0 != dc_file_exist(context, context.get_dbfile()) {
context, error!(
0, "Cannot import backups: Cannot delete the old file.", context,
); 0, "Cannot import backups: Cannot delete the old file.",
} else if !(0 == dc_copy_file(context, backup_to_import, context.get_dbfile())) { );
/* error already logged */ return 0;
/* re-open copied database file */ }
if context.sql.open(&context, as_path(context.get_dbfile()), 0) {
total_files_cnt = dc_sqlite3_query_row::<_, isize>(
context,
&context.sql,
"SELECT COUNT(*) FROM backup_blobs;",
params![],
0,
)
.unwrap_or_default() as usize;
info!(
context,
0, "***IMPORT-in-progress: total_files_cnt={:?}", total_files_cnt,
);
let files = if let Some(mut stmt) = dc_sqlite3_prepare( if 0 == dc_copy_file(context, backup_to_import, context.get_dbfile()) {
context, return 0;
&context.sql, }
"SELECT file_name, file_content FROM backup_blobs ORDER BY id;", /* error already logged */
) { /* re-open copied database file */
stmt.query_map(params![], |row| { if !context.sql.open(&context, as_path(context.get_dbfile()), 0) {
let name: String = row.get(0)?; return 0;
let blob: Vec<u8> = row.get(1)?; }
Ok((name, blob)) let total_files_cnt = dc_sqlite3_query_row::<_, isize>(
}) context,
.map(|res| res.collect::<Vec<_>>()) &context.sql,
.unwrap() "SELECT COUNT(*) FROM backup_blobs;",
} else { params![],
panic!("invalid sql"); 0,
}; )
.unwrap_or_default() as usize;
info!(
context,
0, "***IMPORT-in-progress: total_files_cnt={:?}", total_files_cnt,
);
context
.sql
.query_map(
"SELECT file_name, file_content FROM backup_blobs ORDER BY id;",
params![],
|row| {
let name: String = row.get(0)?;
let blob: Vec<u8> = row.get(1)?;
Ok((name, blob))
},
|files| {
let mut loop_success = true; let mut loop_success = true;
let mut processed_files_cnt = 0;
for file in files { for file in files {
if file.is_err() { if file.is_err() {
@@ -904,21 +905,15 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
break; break;
} }
if loop_success { if !loop_success {
dc_sqlite3_execute( return Err(format_err!("fail").into());
context,
&context.sql,
"DROP TABLE backup_blobs;",
params![],
);
dc_sqlite3_try_execute(context, &context.sql, "VACUUM;");
success = 1;
} }
} dc_sqlite3_execute(context, &context.sql, "DROP TABLE backup_blobs;", params![]);
} dc_sqlite3_try_execute(context, &context.sql, "VACUUM;");
} Ok(())
},
success )
.is_ok() as libc::c_int
} }
/******************************************************************************* /*******************************************************************************
@@ -1266,25 +1261,24 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
unsafe fn export_self_keys(context: &Context, dir: *const libc::c_char) -> libc::c_int { unsafe fn export_self_keys(context: &Context, dir: *const libc::c_char) -> libc::c_int {
let mut export_errors = 0; let mut export_errors = 0;
if let Some(mut stmt) = dc_sqlite3_prepare( context
context, .sql
&context.sql, .query_map(
"SELECT id, public_key, private_key, is_default FROM keypairs;", "SELECT id, public_key, private_key, is_default FROM keypairs;",
) { params![],
let rows = stmt.query_map(params![], |row| { |row| {
let id = row.get(0)?; let id = row.get(0)?;
let public_key_blob: Vec<u8> = row.get(1)?; let public_key_blob: Vec<u8> = row.get(1)?;
let public_key = Key::from_slice(&public_key_blob, KeyType::Public); let public_key = Key::from_slice(&public_key_blob, KeyType::Public);
let private_key_blob: Vec<u8> = row.get(2)?; let private_key_blob: Vec<u8> = row.get(2)?;
let private_key = Key::from_slice(&private_key_blob, KeyType::Private); let private_key = Key::from_slice(&private_key_blob, KeyType::Private);
let is_default = row.get(3)?; let is_default = row.get(3)?;
Ok((id, public_key, private_key, is_default)) Ok((id, public_key, private_key, is_default))
}); },
|keys| {
if let Ok(keys) = rows { for key_pair in keys {
for key_pair in keys { let (id, public_key, private_key, is_default) = key_pair?;
if let Ok((id, public_key, private_key, is_default)) = key_pair {
if let Some(key) = public_key { if let Some(key) = public_key {
if 0 == export_key_to_asc_file(context, dir, id, &key, is_default) { if 0 == export_key_to_asc_file(context, dir, id, &key, is_default) {
export_errors += 1; export_errors += 1;
@@ -1300,13 +1294,11 @@ unsafe fn export_self_keys(context: &Context, dir: *const libc::c_char) -> libc:
export_errors += 1; export_errors += 1;
} }
} }
}
} else { Ok(())
return 1; },
} )
} else { .unwrap();
return 1;
}
if export_errors == 0 { if export_errors == 0 {
1 1

View File

@@ -6,6 +6,7 @@ use crate::constants::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_param::*; use crate::dc_param::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::error::Result;
use crate::peerstate::*; use crate::peerstate::*;
use crate::x::*; use crate::x::*;
@@ -44,13 +45,13 @@ impl SQLite {
} }
} }
pub fn execute<P>(&self, sql: &str, params: P) -> rusqlite::Result<usize> pub fn execute<P>(&self, sql: &str, params: P) -> Result<usize>
where where
P: IntoIterator, P: IntoIterator,
P::Item: rusqlite::ToSql, P::Item: rusqlite::ToSql,
{ {
match &*self.connection.read().unwrap() { match &*self.connection.read().unwrap() {
Some(conn) => conn.execute(sql, params), Some(conn) => conn.execute(sql, params).map_err(Into::into),
None => panic!("Querying closed SQLite database"), None => panic!("Querying closed SQLite database"),
} }
} }
@@ -62,18 +63,12 @@ impl SQLite {
/// Prepares and executes the statement and maps a function over the resulting rows. /// 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 /// Then executes the second function over the returned iterator and returns the
/// result of that function. /// result of that function.
pub fn query_map<T, P, F, G, H>( pub fn query_map<T, P, F, G, H>(&self, sql: &str, params: P, f: F, mut g: G) -> Result<H>
&self,
sql: &str,
params: P,
f: F,
mut g: G,
) -> rusqlite::Result<H>
where where
P: IntoIterator, P: IntoIterator,
P::Item: rusqlite::ToSql, P::Item: rusqlite::ToSql,
F: FnMut(&rusqlite::Row) -> rusqlite::Result<T>, F: FnMut(&rusqlite::Row) -> rusqlite::Result<T>,
G: FnMut(rusqlite::MappedRows<F>) -> rusqlite::Result<H>, G: FnMut(rusqlite::MappedRows<F>) -> Result<H>,
{ {
let conn_lock = self.connection.read().unwrap(); let conn_lock = self.connection.read().unwrap();
let conn = conn_lock.as_ref().expect("database closed"); let conn = conn_lock.as_ref().expect("database closed");
@@ -85,7 +80,7 @@ impl SQLite {
/// Return `true` if a query in the SQL statement it executes returns one or more /// 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. /// rows and false if the SQL returns an empty set.
pub fn exists<P>(&self, sql: &str, params: P) -> rusqlite::Result<bool> pub fn exists<P>(&self, sql: &str, params: P) -> Result<bool>
where where
P: IntoIterator, P: IntoIterator,
P::Item: rusqlite::ToSql, P::Item: rusqlite::ToSql,
@@ -98,14 +93,14 @@ impl SQLite {
Ok(res) 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) -> Result<T>
where where
P: IntoIterator, P: IntoIterator,
P::Item: rusqlite::ToSql, P::Item: rusqlite::ToSql,
F: FnOnce(&rusqlite::Row) -> rusqlite::Result<T>, F: FnOnce(&rusqlite::Row) -> rusqlite::Result<T>,
{ {
match &*self.connection.read().unwrap() { match &*self.connection.read().unwrap() {
Some(conn) => conn.query_row(sql, params, f), Some(conn) => conn.query_row(sql, params, f).map_err(Into::into),
None => panic!("Querying closed SQLite database"), None => panic!("Querying closed SQLite database"),
} }
} }
@@ -127,7 +122,7 @@ impl SQLite {
// Return 1 -> success // Return 1 -> success
// Return 0 -> failure // Return 0 -> failure
pub fn dc_sqlite3_open( fn dc_sqlite3_open(
context: &Context, context: &Context,
sql: &SQLite, sql: &SQLite,
dbfile: impl AsRef<std::path::Path>, dbfile: impl AsRef<std::path::Path>,
@@ -773,26 +768,23 @@ pub fn dc_sqlite3_open(
} }
if 0 != recalc_fingerprints { if 0 != recalc_fingerprints {
let rows = if let Some(mut stmt) = sql.query_map(
dc_sqlite3_prepare(context, sql, "SELECT addr FROM acpeerstates;") "SELECT addr FROM acpeerstates;",
{ params![],
stmt.query_map(params![], |row| row.get::<_, String>(0)) |row| row.get::<_, String>(0),
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()) |addrs| {
.ok() for addr in addrs {
} else { if let Some(ref mut peerstate) =
None Peerstate::from_addr(context, sql, &addr?)
}; {
peerstate.recalc_fingerprint();
if let Some(addrs) = rows { peerstate.save_to_db(sql, false);
for addr in addrs { }
if let Some(ref mut peerstate) =
Peerstate::from_addr(context, sql, &addr)
{
peerstate.recalc_fingerprint();
peerstate.save_to_db(sql, false);
} }
} Ok(())
} },
)
.unwrap();
} }
if 0 != update_file_paths { if 0 != update_file_paths {
let repl_from = dc_sqlite3_get_config( let repl_from = dc_sqlite3_get_config(
@@ -854,28 +846,23 @@ pub fn dc_sqlite3_set_config(
let good; let good;
if let Some(ref value) = value { if let Some(ref value) = value {
if let Some(exists) = let exists = sql
dc_sqlite3_prepare(context, sql, "SELECT value FROM config WHERE keyname=?;") .exists("SELECT value FROM config WHERE keyname=?;", params![])
.and_then(|mut stmt| stmt.exists(params![]).ok()) .unwrap_or_default();
{ if exists {
if exists { good = dc_sqlite3_execute(
good = dc_sqlite3_execute( context,
context, sql,
sql, "UPDATE config SET value=? WHERE keyname=?;",
"UPDATE config SET value=? WHERE keyname=?;", params![value, key],
params![value, key], );
);
} else {
good = dc_sqlite3_execute(
context,
sql,
"INSERT INTO config (keyname, value) VALUES (?, ?);",
params![key, value],
);
}
} else { } else {
error!(context, 0, "dc_sqlite3_set_config(): Cannot read value.",); good = dc_sqlite3_execute(
return 0; context,
sql,
"INSERT INTO config (keyname, value) VALUES (?, ?);",
params![key, value],
);
} }
} else { } else {
good = dc_sqlite3_execute( good = dc_sqlite3_execute(
@@ -896,19 +883,14 @@ pub fn dc_sqlite3_set_config(
// TODO: Remove the option from the return type // TODO: Remove the option from the return type
pub fn dc_sqlite3_prepare<'a>( pub fn dc_sqlite3_prepare<'a>(
context: &Context, _context: &Context,
sql: &'a SQLite, _sql: &'a SQLite,
querystr: &'a str, _querystr: &'a str,
) -> Option<Statement<'a>> { ) -> Option<Statement<'a>> {
// TODO: remove once it is not used anymore // TODO: remove once it is not used anymore
unimplemented!() unimplemented!()
} }
pub fn dc_sqlite3_is_open(sql: &SQLite) -> libc::c_int {
sql.is_open() as libc::c_int
}
/* the returned string must be free()'d, returns NULL on errors */
pub fn dc_sqlite3_get_config( pub fn dc_sqlite3_get_config(
context: &Context, context: &Context,
sql: &SQLite, sql: &SQLite,
@@ -929,7 +911,7 @@ pub fn dc_sqlite3_get_config(
} }
pub fn dc_sqlite3_execute<P>( pub fn dc_sqlite3_execute<P>(
context: &Context, _context: &Context,
sql: &SQLite, sql: &SQLite,
querystr: impl AsRef<str>, querystr: impl AsRef<str>,
params: P, params: P,
@@ -938,23 +920,7 @@ where
P: IntoIterator, P: IntoIterator,
P::Item: rusqlite::ToSql, P::Item: rusqlite::ToSql,
{ {
if let Some(mut stmt) = dc_sqlite3_prepare(context, sql, querystr.as_ref()) { sql.execute(querystr.as_ref(), params).is_ok()
match stmt.execute(params) {
Ok(_) => true,
Err(err) => {
error!(
context,
0,
"Cannot execute \"{}\". ({})",
querystr.as_ref(),
err
);
false
}
}
} else {
false
}
} }
// TODO Remove the Option<> from the return type. // TODO Remove the Option<> from the return type.
@@ -1036,22 +1002,18 @@ pub fn dc_sqlite3_try_execute(
querystr: impl AsRef<str>, querystr: impl AsRef<str>,
) -> libc::c_int { ) -> libc::c_int {
// same as dc_sqlite3_execute() but does not pass error to ui // same as dc_sqlite3_execute() but does not pass error to ui
if let Some(mut stmt) = dc_sqlite3_prepare(context, sql, querystr.as_ref()) { match sql.execute(querystr.as_ref(), params![]) {
match stmt.execute(params![]) { Ok(_) => 1,
Ok(_) => 1, Err(err) => {
Err(err) => { warn!(
warn!( context,
context, 0,
0, "Try-execute for \"{}\" failed: {}",
"Try-execute for \"{}\" failed: {}", querystr.as_ref(),
querystr.as_ref(), err,
err, );
); 0
0
}
} }
} else {
0
} }
} }
@@ -1146,18 +1108,23 @@ pub fn dc_housekeeping(context: &Context) {
'i' as i32, 'i' as i32,
); );
if let Some(mut stmt) = dc_sqlite3_prepare(context, &context.sql, "SELECT value FROM config;") { context
match stmt.query_map(params![], |row| row.get::<_, String>(0)) { .sql
Ok(rows) => { .query_map(
"SELECT value FROM config;",
params![],
|row| row.get::<_, String>(0),
|rows| {
for row in rows { for row in rows {
maybe_add_file(&mut files_in_use, row.expect("invalid sql")); maybe_add_file(&mut files_in_use, row?);
} }
} Ok(())
Err(err) => { },
warn!(context, 0, "sql: failed query: {}", err); )
} .unwrap_or_else(|err| {
} warn!(context, 0, "sql: failed query: {}", err);
} });
info!(context, 0, "{} files in use.", files_in_use.len(),); info!(context, 0, "{} files in use.", files_in_use.len(),);
/* go through directory and delete unused files */ /* go through directory and delete unused files */
let p = std::path::Path::new(as_str(context.get_blobdir())); let p = std::path::Path::new(as_str(context.get_blobdir()));
@@ -1285,8 +1252,9 @@ fn maybe_add_from_param(
) { ) {
let param = unsafe { dc_param_new() }; let param = unsafe { dc_param_new() };
if let Some(ref mut stmt) = dc_sqlite3_prepare(context, &context.sql, query) { context
match stmt.query_row(NO_PARAMS, |row| { .sql
.query_row(query, NO_PARAMS, |row| {
let v = to_cstring(row.get::<_, String>(0)?); let v = to_cstring(row.get::<_, String>(0)?);
unsafe { unsafe {
dc_param_set_packed(param, v.as_ptr() as *const libc::c_char); dc_param_set_packed(param, v.as_ptr() as *const libc::c_char);
@@ -1297,13 +1265,11 @@ fn maybe_add_from_param(
} }
} }
Ok(()) Ok(())
}) { })
Ok(_) => {} .unwrap_or_else(|err| {
Err(err) => { warn!(context, 0, "sql: failed to add_from_param: {}", err);
warn!(context, 0, "sql: failed to add_from_param: {}", err); });
}
}
}
unsafe { dc_param_unref(param) }; unsafe { dc_param_unref(param) };
} }

23
src/error.rs Normal file
View File

@@ -0,0 +1,23 @@
use failure::Fail;
#[derive(Debug, Fail)]
pub enum Error {
#[fail(display = "Sqlite Error: {:?}", _0)]
Sql(rusqlite::Error),
#[fail(display = "{:?}", _0)]
Failure(failure::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
impl From<rusqlite::Error> for Error {
fn from(err: rusqlite::Error) -> Error {
Error::Sql(err)
}
}
impl From<failure::Error> for Error {
fn from(err: failure::Error) -> Error {
Error::Failure(err)
}
}

View File

@@ -23,6 +23,7 @@ pub mod dc_log;
pub mod aheader; pub mod aheader;
pub mod constants; pub mod constants;
pub mod context; pub mod context;
pub mod error;
pub mod imap; pub mod imap;
pub mod key; pub mod key;
pub mod keyhistory; pub mod keyhistory;