sqlite-wasm-connector/src/connection.rs

217 lines
6.2 KiB
Rust
Raw Normal View History

2021-09-02 19:20:43 +03:00
use crate::sqlite3_connector as ffi;
2020-09-17 21:19:03 +03:00
2015-05-29 09:44:06 -04:00
use std::marker::PhantomData;
use std::path::Path;
2021-09-02 19:20:43 +03:00
use crate::{Result, Statement};
2015-05-29 09:44:06 -04:00
2015-08-02 22:29:04 -04:00
/// A database connection.
pub struct Connection {
2020-09-17 21:19:03 +03:00
raw: ffi::Sqlite3DbHandle,
phantom: PhantomData<ffi::Sqlite3DbHandle>,
2015-05-29 09:44:06 -04:00
}
2019-06-10 20:29:34 +02:00
/// Flags for opening a database connection.
2019-06-08 19:50:27 +02:00
#[derive(Clone, Copy, Debug)]
2020-09-17 21:19:03 +03:00
pub struct OpenFlags(i32);
2019-06-08 19:50:27 +02:00
2016-11-30 12:53:32 +01:00
unsafe impl Send for Connection {}
impl Connection {
2019-06-08 19:50:27 +02:00
/// Open a read-write connection to a new or existing database.
pub fn open<T: AsRef<Path>>(path: T) -> Result<Connection> {
2019-06-09 07:15:34 +02:00
Connection::open_with_flags(path, OpenFlags::new().set_create().set_read_write())
2015-05-29 09:44:06 -04:00
}
2019-06-10 20:29:34 +02:00
/// Open a database connection with specific flags.
2019-06-09 07:15:34 +02:00
pub fn open_with_flags<T: AsRef<Path>>(path: T, flags: OpenFlags) -> Result<Connection> {
unsafe {
2020-09-17 21:19:03 +03:00
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 {
2020-05-26 20:05:39 +02:00
ffi::SQLITE_OK => {}
2020-09-17 21:19:03 +03:00
code => {
2021-09-02 19:20:43 +03:00
return match crate::last_error(result.db_handle) {
2020-09-17 21:19:03 +03:00
Some(error) => {
ffi::sqlite3_close(result.db_handle);
Err(error)
}
_ => {
ffi::sqlite3_close(result.db_handle);
2021-09-02 19:20:43 +03:00
Err(crate::Error {
2020-09-17 21:19:03 +03:00
code: Some(code as isize),
message: None,
})
}
}
2020-09-17 21:19:03 +03:00
}
}
2020-09-17 21:19:03 +03:00
Ok(Connection {
raw: result.db_handle,
phantom: PhantomData,
})
}
}
2015-08-02 22:29:04 -04:00
/// Execute a statement without processing the resulting rows if any.
#[inline]
2015-08-02 22:29:04 -04:00
pub fn execute<T: AsRef<str>>(&self, statement: T) -> Result<()> {
unsafe {
2020-09-17 21:19:03 +03:00
ok_descr!(
2017-08-22 17:34:03 +02:00
self.raw,
2020-09-17 21:19:03 +03:00
ffi::sqlite3_exec(self.raw, statement.as_ref().into(), 0, 0,)
2017-08-22 17:34:03 +02:00
);
}
Ok(())
}
2015-08-02 22:29:04 -04:00
/// Execute a statement and process the resulting rows as plain text.
///
/// The callback is triggered for each row. If the callback returns `false`,
2015-07-04 09:21:38 -04:00
/// no more rows will be processed. For large queries and non-string data
2015-08-03 17:12:15 -04:00
/// types, prepared statement are highly preferable; see `prepare`.
#[inline]
2015-08-03 17:12:15 -04:00
pub fn iterate<T: AsRef<str>, F>(&self, statement: T, callback: F) -> Result<()>
2017-08-22 17:34:03 +02:00
where
F: FnMut(&[(&str, Option<&str>)]) -> bool,
{
unsafe {
2020-09-17 21:19:03 +03:00
let _callback = Box::new(callback);
ok_descr!(
2017-08-22 17:34:03 +02:00
self.raw,
2020-09-17 21:19:03 +03:00
ffi::sqlite3_exec(self.raw, statement.as_ref().into(), 0, 0,)
2017-08-22 17:34:03 +02:00
);
2015-05-29 09:44:06 -04:00
}
Ok(())
}
2015-05-29 11:24:01 -04:00
/// Create a prepared statement.
#[inline]
2020-09-17 21:19:03 +03:00
pub fn prepare<T: AsRef<str>>(&self, statement: T) -> Result<Statement> {
2021-09-02 19:20:43 +03:00
crate::statement::new(self.raw, statement)
2015-08-02 22:29:04 -04:00
}
2020-06-10 20:20:43 +02:00
/// Return the number of rows inserted, updated, or deleted by the most
/// recent INSERT, UPDATE, or DELETE statement.
#[inline]
pub fn changes(&self) -> usize {
2020-06-10 20:20:59 +02:00
unsafe { ffi::sqlite3_changes(self.raw) as usize }
}
2020-06-10 20:20:43 +02:00
/// Return the total number of rows inserted, updated, and deleted by all
/// INSERT, UPDATE, and DELETE statements since the connection was opened.
#[inline]
pub fn total_changes(&self) -> usize {
2020-06-10 20:20:59 +02:00
unsafe { ffi::sqlite3_total_changes(self.raw) as usize }
}
/// Set an implicit callback for handling busy events that tries to repeat
/// rejected operations until a timeout expires.
#[inline]
pub fn set_busy_timeout(&mut self, milliseconds: usize) -> Result<()> {
2017-08-22 17:34:03 +02:00
unsafe {
2020-09-17 21:19:03 +03:00
ok_raw!(
2017-08-22 17:34:03 +02:00
self.raw,
2020-09-17 21:19:03 +03:00
ffi::sqlite3_busy_timeout(self.raw, milliseconds as _)
2017-08-23 10:13:05 +02:00
);
}
Ok(())
}
2017-08-23 10:13:59 +02:00
/// Return the raw pointer.
#[inline]
2020-09-17 21:19:03 +03:00
pub fn as_raw(&self) -> ffi::Sqlite3DbHandle {
2017-08-23 10:13:59 +02:00
self.raw
}
2015-05-29 09:44:06 -04:00
}
impl Drop for Connection {
#[inline]
#[allow(unused_must_use)]
fn drop(&mut self) {
unsafe { ffi::sqlite3_close(self.raw) };
}
2015-05-29 09:44:06 -04:00
}
2019-06-09 07:15:34 +02:00
impl OpenFlags {
2019-06-10 20:29:34 +02:00
/// Create flags for opening a database connection.
2019-06-08 19:50:27 +02:00
#[inline]
pub fn new() -> Self {
2019-06-09 07:15:34 +02:00
OpenFlags(0)
2019-06-08 19:50:27 +02:00
}
/// Create the database if it does not already exist.
pub fn set_create(mut self) -> Self {
self.0 |= ffi::SQLITE_OPEN_CREATE;
self
}
2019-06-08 20:15:44 +02:00
/// 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
}
2019-06-08 19:50:27 +02:00
/// Open the database for reading only.
pub fn set_read_only(mut self) -> Self {
2019-06-08 20:42:31 +02:00
self.0 |= ffi::SQLITE_OPEN_READONLY;
2019-06-08 19:50:27 +02:00
self
}
/// Open the database for reading and writing.
pub fn set_read_write(mut self) -> Self {
self.0 |= ffi::SQLITE_OPEN_READWRITE;
self
}
}
2020-09-17 21:19:03 +03:00
/*
2017-08-22 17:34:03 +02:00
extern "C" fn process_callback<F>(
callback: *mut c_void,
2020-09-17 21:19:03 +03:00
count: i32,
2017-08-22 17:34:03 +02:00
values: *mut *mut c_char,
columns: *mut *mut c_char,
2020-09-17 21:19:03 +03:00
) -> i32
2017-08-22 17:34:03 +02:00
where
F: FnMut(&[(&str, Option<&str>)]) -> bool,
{
2015-05-29 09:44:06 -04:00
unsafe {
let mut pairs = Vec::with_capacity(count as usize);
for i in 0..(count as isize) {
let column = {
let pointer = *columns.offset(i);
debug_assert!(!pointer.is_null());
c_str_to_str!(pointer).unwrap()
};
let value = {
let pointer = *values.offset(i);
if pointer.is_null() {
None
} else {
Some(c_str_to_str!(pointer).unwrap())
}
};
2015-05-29 09:44:06 -04:00
pairs.push((column, value));
}
2017-08-22 17:34:03 +02:00
if (*(callback as *mut F))(&pairs) {
0
} else {
1
}
2015-05-29 09:44:06 -04:00
}
}
2020-09-17 21:19:03 +03:00
*/