diff --git a/src/connection.rs b/src/connection.rs index b956477..d0798d2 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -12,35 +12,26 @@ pub struct Connection { phantom: PhantomData, } +/// Flags for opening a database connection. +#[derive(Clone, Copy, Debug)] +pub struct OpenFlags(c_int); + unsafe impl Send for Connection {} impl Connection { - /// Open a connection to a new or existing database. + /// Open a read-write connection to a new or existing database. pub fn open>(path: T) -> Result { - let mut raw = 0 as *mut _; - unsafe { - ok!(ffi::sqlite3_open_v2( - path_to_cstr!(path.as_ref()).as_ptr(), - &mut raw, - ffi::SQLITE_OPEN_CREATE | ffi::SQLITE_OPEN_READWRITE, - 0 as *const _, - )); - } - Ok(Connection { - raw: raw, - busy_callback: None, - phantom: PhantomData, - }) + Connection::open_with_flags(path, OpenFlags::new().set_create().set_read_write()) } - /// Open a read-only connection to an existing database. - pub fn open_readonly>(path: T) -> Result { + /// Open a database connection with specific flags. + pub fn open_with_flags>(path: T, flags: OpenFlags) -> Result { let mut raw = 0 as *mut _; unsafe { ok!(ffi::sqlite3_open_v2( path_to_cstr!(path.as_ref()).as_ptr(), &mut raw, - ffi::SQLITE_OPEN_READONLY, + flags.0, 0 as *const _, )); } @@ -166,6 +157,48 @@ impl Drop for Connection { } } +impl OpenFlags { + /// Create flags for opening a database connection. + #[inline] + pub fn new() -> Self { + OpenFlags(0) + } + + /// Create the database if it does not already exist. + pub fn set_create(mut self) -> Self { + self.0 |= ffi::SQLITE_OPEN_CREATE; + self + } + + /// Open the database in the serialized [threading mode][1]. + /// + /// [1]: https://www.sqlite.org/threadsafe.html + pub fn set_full_mutex(mut self) -> Self { + self.0 |= ffi::SQLITE_OPEN_FULLMUTEX; + self + } + + /// Opens the database in the multi-thread [threading mode][1]. + /// + /// [1]: https://www.sqlite.org/threadsafe.html + pub fn set_no_mutex(mut self) -> Self { + self.0 |= ffi::SQLITE_OPEN_NOMUTEX; + self + } + + /// Open the database for reading only. + pub fn set_read_only(mut self) -> Self { + self.0 |= ffi::SQLITE_OPEN_READONLY; + self + } + + /// Open the database for reading and writing. + pub fn set_read_write(mut self) -> Self { + self.0 |= ffi::SQLITE_OPEN_READWRITE; + self + } +} + extern "C" fn busy_callback(callback: *mut c_void, attempts: c_int) -> c_int where F: FnMut(usize) -> bool, diff --git a/src/lib.rs b/src/lib.rs index 84dcb5d..662cc08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -294,21 +294,16 @@ mod cursor; mod statement; pub use connection::Connection; +pub use connection::OpenFlags; pub use cursor::Cursor; pub use statement::{Bindable, Readable, State, Statement}; -/// Open a connection to a new or existing database. +/// Open a read-write connection to a new or existing database. #[inline] pub fn open>(path: T) -> Result { Connection::open(path) } -/// Open a read-only connection to an existing database. -#[inline] -pub fn open_readonly>(path: T) -> Result { - Connection::open_readonly(path) -} - /// Return the version number of SQLite. /// /// For instance, the version `3.8.11.1` corresponds to the integer `3008011`. diff --git a/tests/lib.rs b/tests/lib.rs index 0c38b03..28827d5 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,7 +1,7 @@ extern crate sqlite; extern crate temporary; -use sqlite::{Connection, State, Type, Value}; +use sqlite::{Connection, OpenFlags, State, Type, Value}; use std::path::Path; macro_rules! ok(($result:expr) => ($result.unwrap())); @@ -40,6 +40,22 @@ fn connection_iterate() { assert!(done); } +#[test] +fn connection_open_with_flags() { + use temporary::Directory; + + let directory = ok!(Directory::new("sqlite")); + let path = directory.path().join("database.sqlite3"); + setup_users(&path); + + let flags = OpenFlags::new().set_read_only(); + let connection = ok!(Connection::open_with_flags(path, flags)); + match connection.execute("INSERT INTO users VALUES (2, 'Bob', NULL, NULL)") { + Err(_) => {} + _ => unreachable!(), + } +} + #[test] fn connection_set_busy_handler() { use std::thread;