fce_sqlite_connector/
connection.rs

1use sqlite3_connector as ffi;
2
3use std::marker::PhantomData;
4use std::path::Path;
5
6use {Result, Statement};
7
8/// A database connection.
9pub struct Connection {
10    raw: ffi::Sqlite3DbHandle,
11    phantom: PhantomData<ffi::Sqlite3DbHandle>,
12}
13
14/// Flags for opening a database connection.
15#[derive(Clone, Copy, Debug)]
16pub struct OpenFlags(i32);
17
18unsafe impl Send for Connection {}
19
20impl Connection {
21    /// Open a read-write connection to a new or existing database.
22    pub fn open<T: AsRef<Path>>(path: T) -> Result<Connection> {
23        Connection::open_with_flags(path, OpenFlags::new().set_create().set_read_write())
24    }
25
26    /// Open a database connection with specific flags.
27    pub fn open_with_flags<T: AsRef<Path>>(path: T, flags: OpenFlags) -> Result<Connection> {
28        unsafe {
29            let path = path.as_ref();
30            let path = path.to_string_lossy().into_owned();
31            let result = ffi::sqlite3_open_v2(path, flags.0, String::new());
32
33            match result.ret_code {
34                ffi::SQLITE_OK => {}
35                code => {
36                    return match ::last_error(result.db_handle) {
37                        Some(error) => {
38                            ffi::sqlite3_close(result.db_handle);
39                            Err(error)
40                        }
41                        _ => {
42                            ffi::sqlite3_close(result.db_handle);
43                            Err(::Error {
44                                code: Some(code as isize),
45                                message: None,
46                            })
47                        }
48                    }
49                }
50            }
51
52            Ok(Connection {
53                raw: result.db_handle,
54                phantom: PhantomData,
55            })
56        }
57    }
58
59    /// Execute a statement without processing the resulting rows if any.
60    #[inline]
61    pub fn execute<T: AsRef<str>>(&self, statement: T) -> Result<()> {
62        unsafe {
63            ok_descr!(
64                self.raw,
65                ffi::sqlite3_exec(self.raw, statement.as_ref().into(), 0, 0,)
66            );
67        }
68        Ok(())
69    }
70
71    /// Execute a statement and process the resulting rows as plain text.
72    ///
73    /// The callback is triggered for each row. If the callback returns `false`,
74    /// no more rows will be processed. For large queries and non-string data
75    /// types, prepared statement are highly preferable; see `prepare`.
76    #[inline]
77    pub fn iterate<T: AsRef<str>, F>(&self, statement: T, callback: F) -> Result<()>
78    where
79        F: FnMut(&[(&str, Option<&str>)]) -> bool,
80    {
81        unsafe {
82            let _callback = Box::new(callback);
83            ok_descr!(
84                self.raw,
85                ffi::sqlite3_exec(self.raw, statement.as_ref().into(), 0, 0,)
86            );
87        }
88        Ok(())
89    }
90
91    /// Create a prepared statement.
92    #[inline]
93    pub fn prepare<T: AsRef<str>>(&self, statement: T) -> Result<Statement> {
94        ::statement::new(self.raw, statement)
95    }
96
97    /// Return the number of rows inserted, updated, or deleted by the most
98    /// recent INSERT, UPDATE, or DELETE statement.
99    #[inline]
100    pub fn changes(&self) -> usize {
101        unsafe { ffi::sqlite3_changes(self.raw) as usize }
102    }
103
104    /// Return the total number of rows inserted, updated, and deleted by all
105    /// INSERT, UPDATE, and DELETE statements since the connection was opened.
106    #[inline]
107    pub fn total_changes(&self) -> usize {
108        unsafe { ffi::sqlite3_total_changes(self.raw) as usize }
109    }
110
111    /// Set an implicit callback for handling busy events that tries to repeat
112    /// rejected operations until a timeout expires.
113    #[inline]
114    pub fn set_busy_timeout(&mut self, milliseconds: usize) -> Result<()> {
115        unsafe {
116            ok_raw!(
117                self.raw,
118                ffi::sqlite3_busy_timeout(self.raw, milliseconds as _)
119            );
120        }
121        Ok(())
122    }
123
124    /// Return the raw pointer.
125    #[inline]
126    pub fn as_raw(&self) -> ffi::Sqlite3DbHandle {
127        self.raw
128    }
129}
130
131impl Drop for Connection {
132    #[inline]
133    #[allow(unused_must_use)]
134    fn drop(&mut self) {
135        unsafe { ffi::sqlite3_close(self.raw) };
136    }
137}
138
139impl OpenFlags {
140    /// Create flags for opening a database connection.
141    #[inline]
142    pub fn new() -> Self {
143        OpenFlags(0)
144    }
145
146    /// Create the database if it does not already exist.
147    pub fn set_create(mut self) -> Self {
148        self.0 |= ffi::SQLITE_OPEN_CREATE;
149        self
150    }
151
152    /// Open the database in the serialized [threading mode][1].
153    ///
154    /// [1]: https://www.sqlite.org/threadsafe.html
155    pub fn set_full_mutex(mut self) -> Self {
156        self.0 |= ffi::SQLITE_OPEN_FULLMUTEX;
157        self
158    }
159
160    /// Opens the database in the multi-thread [threading mode][1].
161    ///
162    /// [1]: https://www.sqlite.org/threadsafe.html
163    pub fn set_no_mutex(mut self) -> Self {
164        self.0 |= ffi::SQLITE_OPEN_NOMUTEX;
165        self
166    }
167
168    /// Open the database for reading only.
169    pub fn set_read_only(mut self) -> Self {
170        self.0 |= ffi::SQLITE_OPEN_READONLY;
171        self
172    }
173
174    /// Open the database for reading and writing.
175    pub fn set_read_write(mut self) -> Self {
176        self.0 |= ffi::SQLITE_OPEN_READWRITE;
177        self
178    }
179}
180
181/*
182extern "C" fn process_callback<F>(
183    callback: *mut c_void,
184    count: i32,
185    values: *mut *mut c_char,
186    columns: *mut *mut c_char,
187) -> i32
188where
189    F: FnMut(&[(&str, Option<&str>)]) -> bool,
190{
191    unsafe {
192        let mut pairs = Vec::with_capacity(count as usize);
193        for i in 0..(count as isize) {
194            let column = {
195                let pointer = *columns.offset(i);
196                debug_assert!(!pointer.is_null());
197                c_str_to_str!(pointer).unwrap()
198            };
199            let value = {
200                let pointer = *values.offset(i);
201                if pointer.is_null() {
202                    None
203                } else {
204                    Some(c_str_to_str!(pointer).unwrap())
205                }
206            };
207            pairs.push((column, value));
208        }
209        if (*(callback as *mut F))(&pairs) {
210            0
211        } else {
212            1
213        }
214    }
215}
216*/