use sqlite3_connector as ffi;
use std::marker::PhantomData;
use std::path::Path;
use {Result, Statement};
pub struct Connection {
raw: ffi::Sqlite3DbHandle,
phantom: PhantomData<ffi::Sqlite3DbHandle>,
}
#[derive(Clone, Copy, Debug)]
pub struct OpenFlags(i32);
unsafe impl Send for Connection {}
impl Connection {
pub fn open<T: AsRef<Path>>(path: T) -> Result<Connection> {
Connection::open_with_flags(path, OpenFlags::new().set_create().set_read_write())
}
pub fn open_with_flags<T: AsRef<Path>>(path: T, flags: OpenFlags) -> Result<Connection> {
unsafe {
let path = path.as_ref();
let path = path.to_string_lossy().into_owned();
let result = ffi::sqlite3_open_v2(path, flags.0, String::new());
match result.ret_code {
ffi::SQLITE_OK => {}
code => {
return match ::last_error(result.db_handle) {
Some(error) => {
ffi::sqlite3_close(result.db_handle);
Err(error)
}
_ => {
ffi::sqlite3_close(result.db_handle);
Err(::Error {
code: Some(code as isize),
message: None,
})
}
}
}
}
Ok(Connection {
raw: result.db_handle,
phantom: PhantomData,
})
}
}
#[inline]
pub fn execute<T: AsRef<str>>(&self, statement: T) -> Result<()> {
unsafe {
ok_descr!(
self.raw,
ffi::sqlite3_exec(self.raw, statement.as_ref().into(), 0, 0,)
);
}
Ok(())
}
#[inline]
pub fn iterate<T: AsRef<str>, F>(&self, statement: T, callback: F) -> Result<()>
where
F: FnMut(&[(&str, Option<&str>)]) -> bool,
{
unsafe {
let _callback = Box::new(callback);
ok_descr!(
self.raw,
ffi::sqlite3_exec(self.raw, statement.as_ref().into(), 0, 0,)
);
}
Ok(())
}
#[inline]
pub fn prepare<T: AsRef<str>>(&self, statement: T) -> Result<Statement> {
::statement::new(self.raw, statement)
}
#[inline]
pub fn changes(&self) -> usize {
unsafe { ffi::sqlite3_changes(self.raw) as usize }
}
#[inline]
pub fn total_changes(&self) -> usize {
unsafe { ffi::sqlite3_total_changes(self.raw) as usize }
}
#[inline]
pub fn set_busy_timeout(&mut self, milliseconds: usize) -> Result<()> {
unsafe {
ok_raw!(
self.raw,
ffi::sqlite3_busy_timeout(self.raw, milliseconds as _)
);
}
Ok(())
}
#[inline]
pub fn as_raw(&self) -> ffi::Sqlite3DbHandle {
self.raw
}
}
impl Drop for Connection {
#[inline]
#[allow(unused_must_use)]
fn drop(&mut self) {
unsafe { ffi::sqlite3_close(self.raw) };
}
}
impl OpenFlags {
#[inline]
pub fn new() -> Self {
OpenFlags(0)
}
pub fn set_create(mut self) -> Self {
self.0 |= ffi::SQLITE_OPEN_CREATE;
self
}
pub fn set_full_mutex(mut self) -> Self {
self.0 |= ffi::SQLITE_OPEN_FULLMUTEX;
self
}
pub fn set_no_mutex(mut self) -> Self {
self.0 |= ffi::SQLITE_OPEN_NOMUTEX;
self
}
pub fn set_read_only(mut self) -> Self {
self.0 |= ffi::SQLITE_OPEN_READONLY;
self
}
pub fn set_read_write(mut self) -> Self {
self.0 |= ffi::SQLITE_OPEN_READWRITE;
self
}
}