sqlite_ll/
connection.rs

1use core::ffi::CStr;
2use core::ffi::{c_int, c_uint, c_void};
3use core::mem::MaybeUninit;
4use core::ops::BitOr;
5use core::ptr;
6use core::ptr::NonNull;
7
8#[cfg(feature = "std")]
9use std::path::Path;
10
11use crate::State;
12use crate::error::{Error, Result};
13use crate::owned::Owned;
14use crate::statement::Statement;
15use crate::utils::sqlite3_try;
16
17use sqlite3_sys as ffi;
18
19/// A collection of flags use to prepare a statement.
20pub struct Prepare(c_uint);
21
22impl Prepare {
23    /// No flags.
24    ///
25    /// This provides the default behavior when preparing a statement.
26    pub const EMPTY: Self = Self(0);
27
28    /// The PERSISTENT flag is a hint to the query planner that the prepared
29    /// statement will be retained for a long time and probably reused many
30    /// times. Without this flag, sqlite3_prepare_v3() and
31    /// sqlite3_prepare16_v3() assume that the prepared statement will be used
32    /// just once or at most a few times and then destroyed using
33    /// sqlite3_finalize() relatively soon. The current implementation acts on
34    /// this hint by avoiding the use of lookaside memory so as not to deplete
35    /// the limited store of lookaside memory. Future versions of SQLite may act
36    /// on this hint differently.
37    pub const PERSISTENT: Self = Self(ffi::SQLITE_PREPARE_PERSISTENT as c_uint);
38
39    /// The NORMALIZE flag is a no-op. This flag used to be required for any
40    /// prepared statement that wanted to use the sqlite3_normalized_sql()
41    /// interface. However, the sqlite3_normalized_sql() interface is now
42    /// available to all prepared statements, regardless of whether or not they
43    /// use this flag.
44    pub const NORMALIZE: Self = Self(ffi::SQLITE_PREPARE_NORMALIZE as c_uint);
45
46    /// The NO_VTAB flag causes the SQL compiler to return an error if the
47    /// statement uses any virtual tables.
48    pub const NO_VTAB: Self = Self(ffi::SQLITE_PREPARE_NO_VTAB as c_uint);
49}
50
51impl BitOr for Prepare {
52    type Output = Self;
53
54    fn bitor(self, rhs: Self) -> Self::Output {
55        Self(self.0 | rhs.0)
56    }
57}
58
59/// A sqlite database connection.
60///
61/// Connections are not thread-safe objects.
62///
63/// # Examples
64///
65/// Opening a connection to a filesystem path:
66///
67/// ```no_run
68/// use sqlite_ll::Connection;
69///
70/// let c = Connection::open("database.db")?;
71/// c.execute("CREATE TABLE test (id INTEGER);")?;
72/// # Ok::<_, sqlite_ll::Error>(())
73/// ```
74///
75/// Opening an in-memory database:
76///
77/// ```
78/// use sqlite_ll::Connection;
79///
80/// let c = Connection::memory()?;
81/// c.execute("CREATE TABLE test (id INTEGER);")?;
82/// # Ok::<_, sqlite_ll::Error>(())
83/// ```
84pub struct Connection {
85    raw: NonNull<ffi::sqlite3>,
86    busy_callback: Option<Owned>,
87}
88
89/// Connection is `Send`.
90unsafe impl Send for Connection {}
91
92impl Connection {
93    /// Open a read-write connection to a new or existing database.
94    #[cfg(feature = "std")]
95    pub fn open(path: impl AsRef<Path>) -> Result<Connection> {
96        OpenOptions::new().set_create().set_read_write().open(path)
97    }
98
99    /// Open an in-memory database.
100    pub fn memory() -> Result<Connection> {
101        OpenOptions::new().set_create().set_read_write().memory()
102    }
103
104    /// Execute a statement without processing the resulting rows if any.
105    #[inline]
106    pub fn execute(&self, stmt: impl AsRef<str>) -> Result<()> {
107        let stmt = stmt.as_ref();
108
109        unsafe {
110            let mut ptr = stmt.as_ptr().cast();
111            let mut len = stmt.len();
112
113            while len > 0 {
114                let mut raw = MaybeUninit::uninit();
115                let mut rest = MaybeUninit::uninit();
116
117                let l = i32::try_from(len).unwrap_or(i32::MAX);
118
119                let res = ffi::sqlite3_prepare_v3(
120                    self.raw.as_ptr(),
121                    ptr,
122                    l,
123                    0,
124                    raw.as_mut_ptr(),
125                    rest.as_mut_ptr(),
126                );
127
128                if res != ffi::SQLITE_OK {
129                    return Err(Error::new(ffi::sqlite3_errcode(self.raw.as_ptr())));
130                }
131
132                let rest = rest.assume_init();
133
134                // If statement is null then it's simply empty, so we can safely
135                // skip it, otherwise iterate over all rows.
136                if let Some(raw) = NonNull::new(raw.assume_init()) {
137                    let mut statement = Statement::from_raw(raw);
138                    while let State::Row = statement.step()? {}
139                }
140
141                // Skip over empty statements.
142                let o = rest.offset_from_unsigned(ptr);
143                len -= o;
144                ptr = rest;
145            }
146
147            Ok(())
148        }
149    }
150
151    /// Build a prepared statement.
152    ///
153    /// This is the same as calling `prepare_with` with `Prepare::EMPTY`.
154    ///
155    /// The database connection will be kept open for the lifetime of this
156    /// statement.
157    ///
158    /// # Errors
159    ///
160    /// If the prepare call contains multiple statements, it will error. To
161    /// execute multiple statements, use [`execute`] instead.
162    ///
163    /// ```
164    /// use sqlite_ll::{Connection, Code};
165    ///
166    /// let c = Connection::memory()?;
167    ///
168    /// let e = c.prepare(
169    ///     "
170    ///     CREATE TABLE test (id INTEGER) /* test */;
171    ///     INSERT INTO test (id) VALUES (1);
172    ///     "
173    /// ).unwrap_err();
174    ///
175    /// assert_eq!(e.code(), Code::ERROR);
176    /// # Ok::<_, sqlite_ll::Error>(())
177    /// ```
178    ///
179    /// [`execute`]: Self::execute
180    ///
181    /// # Examples
182    ///
183    /// ```
184    /// use sqlite_ll::{Connection, State, Prepare};
185    ///
186    /// let c = Connection::memory()?;
187    /// c.execute("CREATE TABLE test (id INTEGER);")?;
188    ///
189    /// let mut insert_stmt = c.prepare("INSERT INTO test (id) VALUES (?);")?;
190    /// let mut query_stmt = c.prepare("SELECT id FROM test;")?;
191    ///
192    /// drop(c);
193    ///
194    /// insert_stmt.reset()?;
195    /// insert_stmt.bind(1, 42)?;
196    /// assert_eq!(insert_stmt.step()?, State::Done);
197    ///
198    /// query_stmt.reset()?;
199    ///
200    /// while let State::Row = query_stmt.step()? {
201    ///     let id: i64 = query_stmt.read(0)?;
202    ///     assert_eq!(id, 42);
203    /// }
204    /// # Ok::<_, sqlite_ll::Error>(())
205    /// ```
206    #[inline]
207    pub fn prepare(&self, stmt: impl AsRef<str>) -> Result<Statement> {
208        self.prepare_with(stmt, Prepare::EMPTY)
209    }
210
211    /// Build a prepared statement with custom flags.
212    ///
213    /// For long-running statements it is recommended that they have the
214    /// [`Prepare::PERSISTENT`] flag set.
215    ///
216    /// The database connection will be kept open for the lifetime of this
217    /// statement.
218    ///
219    /// # Errors
220    ///
221    /// If the prepare call contains multiple statements, it will error. To
222    /// execute multiple statements, use [`execute`] instead.
223    ///
224    /// ```
225    /// use sqlite_ll::{Connection, Code, Prepare};
226    ///
227    /// let c = Connection::memory()?;
228    ///
229    /// let e = c.prepare_with(
230    ///     "
231    ///     CREATE TABLE test (id INTEGER) /* test */;
232    ///     INSERT INTO test (id) VALUES (1);
233    ///     ",
234    ///     Prepare::PERSISTENT
235    /// ).unwrap_err();
236    /// assert_eq!(e.code(), Code::ERROR);
237    /// # Ok::<_, sqlite_ll::Error>(())
238    /// ```
239    ///
240    /// [`execute`]: Self::execute
241    ///
242    /// # Examples
243    ///
244    /// ```
245    /// use sqlite_ll::{Connection, State, Prepare};
246    ///
247    /// let c = Connection::memory()?;
248    /// c.execute("CREATE TABLE test (id INTEGER);")?;
249    ///
250    /// let mut insert_stmt = c.prepare_with("INSERT INTO test (id) VALUES (?);", Prepare::PERSISTENT)?;
251    /// let mut query_stmt = c.prepare_with("SELECT id FROM test;", Prepare::PERSISTENT)?;
252    ///
253    /// drop(c);
254    ///
255    /// /* .. */
256    ///
257    /// insert_stmt.reset()?;
258    /// insert_stmt.bind(1, 42)?;
259    /// assert_eq!(insert_stmt.step()?, State::Done);
260    ///
261    /// query_stmt.reset()?;
262    ///
263    /// while let State::Row = query_stmt.step()? {
264    ///     let id: i64 = query_stmt.read(0)?;
265    ///     assert_eq!(id, 42);
266    /// }
267    /// # Ok::<_, sqlite_ll::Error>(())
268    /// ```
269    pub fn prepare_with(&self, stmt: impl AsRef<str>, flags: Prepare) -> Result<Statement> {
270        let stmt = stmt.as_ref();
271
272        unsafe {
273            let mut raw = MaybeUninit::uninit();
274            let mut rest = MaybeUninit::uninit();
275
276            let ptr = stmt.as_ptr().cast();
277            let len = i32::try_from(stmt.len()).unwrap_or(i32::MAX);
278
279            sqlite3_try! {
280                ffi::sqlite3_prepare_v3(
281                    self.raw.as_ptr(),
282                    ptr,
283                    len,
284                    flags.0,
285                    raw.as_mut_ptr(),
286                    rest.as_mut_ptr(),
287                )
288            };
289
290            let rest = rest.assume_init();
291
292            let o = rest.offset_from_unsigned(ptr);
293
294            if o != stmt.len() {
295                return Err(Error::new(ffi::SQLITE_ERROR));
296            }
297
298            let raw = ptr::NonNull::new_unchecked(raw.assume_init());
299            Ok(Statement::from_raw(raw))
300        }
301    }
302
303    /// Return the number of rows inserted, updated, or deleted by the most
304    /// recent INSERT, UPDATE, or DELETE statement.
305    #[inline]
306    pub fn change_count(&self) -> usize {
307        unsafe { ffi::sqlite3_changes(self.raw.as_ptr()) as usize }
308    }
309
310    /// Return the total number of rows inserted, updated, and deleted by all
311    /// INSERT, UPDATE, and DELETE statements since the connection was opened.
312    #[inline]
313    pub fn total_change_count(&self) -> usize {
314        unsafe { ffi::sqlite3_total_changes(self.raw.as_ptr()) as usize }
315    }
316
317    /// Set a callback for handling busy events.
318    ///
319    /// The callback is triggered when the database cannot perform an operation
320    /// due to processing of some other request. If the callback returns `true`,
321    /// the operation will be repeated.
322    pub fn set_busy_handler<F>(&mut self, callback: F) -> Result<()>
323    where
324        F: FnMut(usize) -> bool + Send + 'static,
325    {
326        self.remove_busy_handler()?;
327
328        unsafe {
329            let callback = Owned::new(callback)?;
330
331            let result = ffi::sqlite3_busy_handler(
332                self.raw.as_ptr(),
333                Some(busy_callback::<F>),
334                callback.as_ptr().cast(),
335            );
336
337            self.busy_callback = Some(callback);
338            sqlite3_try!(result);
339        }
340
341        Ok(())
342    }
343
344    /// Set an implicit callback for handling busy events that tries to repeat
345    /// rejected operations until a timeout expires.
346    #[inline]
347    pub fn set_busy_timeout(&mut self, ms: c_int) -> Result<()> {
348        unsafe {
349            sqlite3_try! {
350                ffi::sqlite3_busy_timeout(
351                    self.raw.as_ptr(),
352                    ms
353                )
354            };
355        }
356
357        Ok(())
358    }
359
360    /// Remove the callback handling busy events.
361    #[inline]
362    pub fn remove_busy_handler(&mut self) -> Result<()> {
363        unsafe {
364            sqlite3_try! {
365                ffi::sqlite3_busy_handler(
366                    self.raw.as_ptr(),
367                    None,
368                    ptr::null_mut()
369                )
370            };
371        }
372
373        self.busy_callback = None;
374        Ok(())
375    }
376}
377
378impl Drop for Connection {
379    #[inline]
380    #[allow(unused_must_use)]
381    fn drop(&mut self) {
382        self.remove_busy_handler();
383
384        // Will close the connection unconditionally. The database will stay
385        // alive until all associated prepared statements have been closed since
386        // we're using v2.
387        let code = unsafe { ffi::sqlite3_close_v2(self.raw.as_ptr()) };
388        debug_assert_eq!(code, sqlite3_sys::SQLITE_OK);
389    }
390}
391
392/// Options that can be used to customize the opening of a SQLite database.
393#[derive(Default, Clone, Copy, Debug)]
394pub struct OpenOptions {
395    raw: c_int,
396}
397
398impl OpenOptions {
399    /// Create flags for opening a database connection.
400    #[inline]
401    pub fn new() -> Self {
402        Self::default()
403    }
404
405    /// Open a database connection with current flags.
406    ///
407    /// `path` can be a filesystem path, or `:memory:` to construct an in-memory
408    /// database.
409    #[cfg(feature = "std")]
410    pub fn open(&self, path: impl AsRef<Path>) -> Result<Connection> {
411        let path = crate::utils::path_to_cstring(path.as_ref())?;
412        self._open(&path)
413    }
414
415    /// Open an in-memory database connection with current flags.
416    pub fn memory(&self) -> Result<Connection> {
417        self._open(c":memory:")
418    }
419
420    fn _open(&self, path: &CStr) -> Result<Connection> {
421        unsafe {
422            let mut raw = MaybeUninit::uninit();
423            let code = ffi::sqlite3_open_v2(path.as_ptr(), raw.as_mut_ptr(), self.raw, ptr::null());
424            let raw = raw.assume_init();
425
426            if code != ffi::SQLITE_OK {
427                let code = ffi::sqlite3_errcode(raw);
428                ffi::sqlite3_close(raw);
429                return Err(Error::new(code));
430            }
431
432            Ok(Connection {
433                raw: NonNull::new_unchecked(raw),
434                busy_callback: None,
435            })
436        }
437    }
438
439    /// Create the database if it does not already exist.
440    pub fn set_create(mut self) -> Self {
441        self.raw |= ffi::SQLITE_OPEN_CREATE;
442        self
443    }
444
445    /// Open the database in the serialized [threading mode][1].
446    ///
447    /// [1]: https://www.sqlite.org/threadsafe.html
448    pub fn set_full_mutex(mut self) -> Self {
449        self.raw |= ffi::SQLITE_OPEN_FULLMUTEX;
450        self
451    }
452
453    /// Opens the database in the multi-thread [threading mode][1].
454    ///
455    /// [1]: https://www.sqlite.org/threadsafe.html
456    pub fn set_no_mutex(mut self) -> Self {
457        self.raw |= ffi::SQLITE_OPEN_NOMUTEX;
458        self
459    }
460
461    /// Open the database for reading only.
462    pub fn set_read_only(mut self) -> Self {
463        self.raw |= ffi::SQLITE_OPEN_READONLY;
464        self
465    }
466
467    /// Open the database for reading and writing.
468    pub fn set_read_write(mut self) -> Self {
469        self.raw |= ffi::SQLITE_OPEN_READWRITE;
470        self
471    }
472}
473
474extern "C" fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int
475where
476    F: FnMut(usize) -> bool,
477{
478    unsafe {
479        if (*(callback as *mut F))(attempts as usize) {
480            1
481        } else {
482            0
483        }
484    }
485}