Move SQL errors into their own module

This commit is contained in:
Alexander Krotov
2019-11-29 23:06:13 +01:00
committed by Floris Bruynooghe
parent ea8adf39c2
commit 612600278a
9 changed files with 102 additions and 66 deletions

View File

@@ -64,13 +64,15 @@ impl Chat {
);
match res {
Err(err @ crate::error::Error::Sql(rusqlite::Error::QueryReturnedNoRows)) => Err(err),
Err(err @ crate::sql::Error::Sql(rusqlite::Error::QueryReturnedNoRows)) => {
Err(err.into())
}
Err(err) => {
error!(
context,
"chat: failed to load from db {}: {:?}", chat_id, err
);
Err(err)
Err(err.into())
}
Ok(mut chat) => {
match chat.id {
@@ -129,7 +131,8 @@ impl Chat {
&context.sql,
"UPDATE chats SET param=? WHERE id=?",
params![self.param.to_string(), self.id as i32],
)
)?;
Ok(())
}
pub fn get_id(&self) -> u32 {
@@ -681,7 +684,7 @@ pub fn lookup_by_contact_id(context: &Context, contact_id: u32) -> Result<(u32,
"SELECT c.id, c.blocked FROM chats c INNER JOIN chats_contacts j ON c.id=j.chat_id WHERE c.type=100 AND c.id>9 AND j.contact_id=?;",
params![contact_id as i32],
|row| Ok((row.get(0)?, row.get::<_, Option<_>>(1)?.unwrap_or_default())),
)
).map_err(Into::into)
}
pub fn get_by_contact_id(context: &Context, contact_id: u32) -> Result<u32, Error> {
@@ -829,7 +832,8 @@ pub fn unarchive(context: &Context, chat_id: u32) -> Result<(), Error> {
&context.sql,
"UPDATE chats SET archived=0 WHERE id=?",
params![chat_id as i32],
)
)?;
Ok(())
}
/// Send a message defined by a dc_msg_t object to a chat.
@@ -976,7 +980,8 @@ fn do_set_draft(context: &Context, chat_id: u32, msg: &mut Message) -> Result<()
msg.param.to_string(),
1,
],
)
)?;
Ok(())
}
// similar to as dc_set_draft() but does not emit an event
@@ -1688,7 +1693,7 @@ pub fn is_group_explicitly_left(context: &Context, grpid: impl AsRef<str>) -> Re
context.sql.exists(
"SELECT id FROM leftgrps WHERE grpid=?;",
params![grpid.as_ref()],
)
).map_err(Into::into)
}
pub fn set_chat_name(

View File

@@ -7,7 +7,6 @@ use crate::blob::BlobObject;
use crate::constants::DC_VERSION_STR;
use crate::context::Context;
use crate::dc_tools::*;
use crate::error::Error;
use crate::job::*;
use crate::stock::StockMessage;
@@ -113,7 +112,7 @@ impl Context {
/// Set the given config key.
/// If `None` is passed as a value the value is cleared and set to the default if there is one.
pub fn set_config(&self, key: Config, value: Option<&str>) -> Result<(), Error> {
pub fn set_config(&self, key: Config, value: Option<&str>) -> crate::sql::Result<()> {
match key {
Config::Selfavatar if value.is_some() => {
let blob = BlobObject::create_from_path(&self, value.unwrap())?;

View File

@@ -141,7 +141,7 @@ pub enum VerifiedStatus {
}
impl Contact {
pub fn load_from_db(context: &Context, contact_id: u32) -> Result<Self> {
pub fn load_from_db(context: &Context, contact_id: u32) -> crate::sql::Result<Self> {
if contact_id == DC_CONTACT_ID_SELF {
let contact = Contact {
id: contact_id,
@@ -691,7 +691,7 @@ impl Contact {
}
Err(err) => {
error!(context, "delete_contact {} failed ({})", contact_id, err);
return Err(err);
return Err(err.into());
}
}
}
@@ -709,7 +709,7 @@ impl Contact {
/// like "Me" in the selected language and the email address
/// defined by dc_set_config().
pub fn get_by_id(context: &Context, contact_id: u32) -> Result<Contact> {
Contact::load_from_db(context, contact_id)
Ok(Contact::load_from_db(context, contact_id)?)
}
/// Get the ID of the contact.

View File

@@ -2,18 +2,10 @@ use failure::Fail;
#[derive(Debug, Fail)]
pub enum Error {
#[fail(display = "Sqlite Error: {:?}", _0)]
Sql(rusqlite::Error),
#[fail(display = "Sqlite Connection Pool Error: {:?}", _0)]
ConnectionPool(r2d2::Error),
#[fail(display = "{:?}", _0)]
Failure(failure::Error),
#[fail(display = "Sqlite: Connection closed")]
SqlNoConnection,
#[fail(display = "Sqlite: Already open")]
SqlAlreadyOpen,
#[fail(display = "Sqlite: Failed to open")]
SqlFailedToOpen,
#[fail(display = "SQL error: {:?}", _0)]
SqlError(#[cause] crate::sql::Error),
#[fail(display = "{:?}", _0)]
Io(std::io::Error),
#[fail(display = "{:?}", _0)]
@@ -40,9 +32,9 @@ pub enum 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<crate::sql::Error> for Error {
fn from(err: crate::sql::Error) -> Error {
Error::SqlError(err)
}
}
@@ -58,12 +50,6 @@ impl From<failure::Error> for Error {
}
}
impl From<r2d2::Error> for Error {
fn from(err: r2d2::Error) -> Error {
Error::ConnectionPool(err)
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
Error::Io(err)

View File

@@ -462,7 +462,9 @@ fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) -> Resul
|files| {
for (processed_files_cnt, file) in files.enumerate() {
let (file_name, file_blob) = file?;
ensure!(!context.shall_stop_ongoing(), "received stop signal");
if context.shall_stop_ongoing() {
return Ok(false);
}
let mut permille = processed_files_cnt * 1000 / total_files_cnt;
if permille < 10 {
permille = 10
@@ -476,26 +478,25 @@ fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) -> Resul
}
let path_filename = context.get_blobdir().join(file_name);
if dc_write_file(context, &path_filename, &file_blob).is_err() {
bail!(
"Storage full? Cannot write file {} with {} bytes.",
path_filename.display(),
file_blob.len(),
);
} else {
continue;
}
dc_write_file(context, &path_filename, &file_blob)?;
}
Ok(())
Ok(true)
},
);
res.and_then(|_| {
// only delete backup_blobs if all files were successfully extracted
sql::execute(context, &context.sql, "DROP TABLE backup_blobs;", params![])?;
sql::try_execute(context, &context.sql, "VACUUM;").ok();
Ok(())
})
match res {
Ok(all_files_extracted) => {
if all_files_extracted {
// only delete backup_blobs if all files were successfully extracted
sql::execute(context, &context.sql, "DROP TABLE backup_blobs;", params![])?;
sql::try_execute(context, &context.sql, "VACUUM;").ok();
Ok(())
} else {
bail!("received stop signal");
}
}
Err(err) => Err(err.into()),
}
}
/*******************************************************************************
@@ -553,7 +554,7 @@ fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
};
dest_sql.close(context);
res
Ok(res?)
}
fn add_files_to_export(context: &Context, sql: &Sql) -> Result<()> {
@@ -576,16 +577,15 @@ fn add_files_to_export(context: &Context, sql: &Sql) -> Result<()> {
info!(context, "EXPORT: total_files_cnt={}", total_files_cnt);
// scan directory, pass 2: copy files
let dir_handle = std::fs::read_dir(&dir)?;
sql.prepare(
let exported_all_files = sql.prepare(
"INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);",
|mut stmt, _| {
let mut processed_files_cnt = 0;
for entry in dir_handle {
let entry = entry?;
ensure!(
!context.shall_stop_ongoing(),
"canceled during export-files"
);
if context.shall_stop_ongoing() {
return Ok(false);
}
processed_files_cnt += 1;
let permille = max(min(processed_files_cnt * 1000 / total_files_cnt, 990), 10);
context.call_cb(Event::ImexProgress(permille));
@@ -605,9 +605,10 @@ fn add_files_to_export(context: &Context, sql: &Sql) -> Result<()> {
stmt.execute(params![name, buf])?;
}
}
Ok(())
Ok(true)
},
)?;
ensure!(exported_all_files, "canceled during export-files");
Ok(())
}

View File

@@ -534,7 +534,7 @@ pub fn save(
}
Ok(newest_location_id)
},
)
).map_err(Into::into)
}
#[allow(non_snake_case)]

View File

@@ -266,7 +266,7 @@ impl Message {
Ok(msg)
},
)
).map_err(Into::into)
}
pub fn delete_from_db(context: &Context, msg_id: MsgId) {
@@ -1256,7 +1256,7 @@ pub(crate) fn rfc724_mid_exists(
Ok((server_folder, server_uid, msg_id))
},
)
).map_err(Into::into)
}
pub fn update_server_uid(

View File

@@ -8,7 +8,6 @@ use crate::aheader::*;
use crate::chat::*;
use crate::constants::*;
use crate::context::Context;
use crate::error::*;
use crate::key::*;
use crate::sql::{self, Sql};
@@ -385,7 +384,7 @@ impl<'a> Peerstate<'a> {
}
}
pub fn save_to_db(&self, sql: &Sql, create: bool) -> Result<()> {
pub fn save_to_db(&self, sql: &Sql, create: bool) -> crate::sql::Result<()> {
if create {
sql::execute(
self.context,

View File

@@ -1,5 +1,7 @@
//! # SQLite wrapper
use failure::Fail;
use std::collections::HashSet;
use std::sync::{Arc, RwLock};
use std::time::Duration;
@@ -11,10 +13,53 @@ use crate::chat::update_saved_messages_icon;
use crate::constants::ShowEmails;
use crate::context::Context;
use crate::dc_tools::*;
use crate::error::{Error, Result};
use crate::param::*;
use crate::peerstate::*;
#[derive(Debug, Fail)]
pub enum Error {
#[fail(display = "Sqlite Error: {:?}", _0)]
Sql(#[cause] rusqlite::Error),
#[fail(display = "Sqlite Connection Pool Error: {:?}", _0)]
ConnectionPool(#[cause] r2d2::Error),
#[fail(display = "Sqlite: Connection closed")]
SqlNoConnection,
#[fail(display = "Sqlite: Already open")]
SqlAlreadyOpen,
#[fail(display = "Sqlite: Failed to open")]
SqlFailedToOpen,
#[fail(display = "{:?}", _0)]
Io(#[cause] std::io::Error),
#[fail(display = "{:?}", _0)]
BlobError(#[cause] crate::blob::BlobError),
}
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<r2d2::Error> for Error {
fn from(err: r2d2::Error) -> Error {
Error::ConnectionPool(err)
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
Error::Io(err)
}
}
impl From<crate::blob::BlobError> for Error {
fn from(err: crate::blob::BlobError) -> Error {
Error::BlobError(err)
}
}
/// A wrapper around the underlying Sqlite3 object.
#[derive(DebugStub)]
pub struct Sql {
@@ -47,7 +92,7 @@ impl Sql {
pub fn open(&self, context: &Context, dbfile: &std::path::Path, readonly: bool) -> bool {
match open(context, self, dbfile, readonly) {
Ok(_) => true,
Err(Error::SqlAlreadyOpen) => false,
Err(crate::error::Error::SqlError(Error::SqlAlreadyOpen)) => false,
Err(_) => {
self.close(context);
false
@@ -321,14 +366,14 @@ fn open(
sql: &Sql,
dbfile: impl AsRef<std::path::Path>,
readonly: bool,
) -> Result<()> {
) -> crate::error::Result<()> {
if sql.is_open() {
error!(
context,
"Cannot open, database \"{:?}\" already opened.",
dbfile.as_ref(),
);
return Err(Error::SqlAlreadyOpen);
return Err(Error::SqlAlreadyOpen.into());
}
let mut open_flags = OpenFlags::SQLITE_OPEN_NO_MUTEX;
@@ -345,7 +390,8 @@ fn open(
.min_idle(Some(2))
.max_size(10)
.connection_timeout(std::time::Duration::new(60, 0))
.build(mgr)?;
.build(mgr)
.map_err(Error::ConnectionPool)?;
{
*sql.pool.write().unwrap() = Some(pool);
@@ -477,7 +523,7 @@ fn open(
dbfile.as_ref(),
);
// cannot create the tables - maybe we cannot write?
return Err(Error::SqlFailedToOpen);
return Err(Error::SqlFailedToOpen.into());
} else {
sql.set_raw_config_int(context, "dbversion", 0)?;
}