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 database to the given path.
94    ///
95    /// Note that it is possible to open an in-memory database by passing
96    /// `":memory:"` here, this call might require allocating depending on the
97    /// platform, so it should be avoided in favor of using [`memory`]. To avoid
98    /// allocating for regular paths, you can use [`open_c_str`], however you
99    /// are responsible for ensuring the c-string is a valid path.
100    ///
101    /// [`memory`]: Self::memory
102    /// [`open_c_str`]: Self::open_c_str
103    #[cfg(feature = "std")]
104    #[cfg_attr(docsrs, cfg(feature = "std"))]
105    #[inline]
106    pub fn open(path: impl AsRef<Path>) -> Result<Connection> {
107        OpenOptions::new().set_create().set_read_write().open(path)
108    }
109
110    /// Open a database connection with a raw c-string.
111    ///
112    /// This can be used to open in-memory databases by passing `c":memory:"` or
113    /// a regular open call with a filesystem path like
114    /// `c"/path/to/database.sql"`.
115    #[inline]
116    pub fn open_c_str(name: &CStr) -> Result<Connection> {
117        OpenOptions::new()
118            .set_create()
119            .set_read_write()
120            .open_c_str(name)
121    }
122
123    /// Open an in-memory database.
124    #[inline]
125    pub fn memory() -> Result<Connection> {
126        OpenOptions::new().set_create().set_read_write().memory()
127    }
128
129    /// Execute a statement without processing the resulting rows if any.
130    #[inline]
131    pub fn execute(&self, stmt: impl AsRef<str>) -> Result<()> {
132        self._execute(stmt.as_ref())
133    }
134
135    fn _execute(&self, stmt: &str) -> Result<()> {
136        unsafe {
137            let mut ptr = stmt.as_ptr().cast();
138            let mut len = stmt.len();
139
140            while len > 0 {
141                let mut raw = MaybeUninit::uninit();
142                let mut rest = MaybeUninit::uninit();
143
144                let l = i32::try_from(len).unwrap_or(i32::MAX);
145
146                let res = ffi::sqlite3_prepare_v3(
147                    self.raw.as_ptr(),
148                    ptr,
149                    l,
150                    0,
151                    raw.as_mut_ptr(),
152                    rest.as_mut_ptr(),
153                );
154
155                if res != ffi::SQLITE_OK {
156                    return Err(Error::new(ffi::sqlite3_errcode(self.raw.as_ptr())));
157                }
158
159                let rest = rest.assume_init();
160
161                // If statement is null then it's simply empty, so we can safely
162                // skip it, otherwise iterate over all rows.
163                if let Some(raw) = NonNull::new(raw.assume_init()) {
164                    let mut statement = Statement::from_raw(raw);
165                    while let State::Row = statement.step()? {}
166                }
167
168                // Skip over empty statements.
169                let o = rest.offset_from_unsigned(ptr);
170                len -= o;
171                ptr = rest;
172            }
173
174            Ok(())
175        }
176    }
177
178    /// Build a prepared statement.
179    ///
180    /// This is the same as calling `prepare_with` with `Prepare::EMPTY`.
181    ///
182    /// The database connection will be kept open for the lifetime of this
183    /// statement.
184    ///
185    /// # Errors
186    ///
187    /// If the prepare call contains multiple statements, it will error. To
188    /// execute multiple statements, use [`execute`] instead.
189    ///
190    /// ```
191    /// use sqlite_ll::{Connection, Code};
192    ///
193    /// let c = Connection::memory()?;
194    ///
195    /// let e = c.prepare(
196    ///     "
197    ///     CREATE TABLE test (id INTEGER) /* test */;
198    ///     INSERT INTO test (id) VALUES (1);
199    ///     "
200    /// ).unwrap_err();
201    ///
202    /// assert_eq!(e.code(), Code::ERROR);
203    /// # Ok::<_, sqlite_ll::Error>(())
204    /// ```
205    ///
206    /// [`execute`]: Self::execute
207    ///
208    /// # Examples
209    ///
210    /// ```
211    /// use sqlite_ll::{Connection, State, Prepare};
212    ///
213    /// let c = Connection::memory()?;
214    /// c.execute("CREATE TABLE test (id INTEGER);")?;
215    ///
216    /// let mut insert_stmt = c.prepare("INSERT INTO test (id) VALUES (?);")?;
217    /// let mut query_stmt = c.prepare("SELECT id FROM test;")?;
218    ///
219    /// drop(c);
220    ///
221    /// insert_stmt.reset()?;
222    /// insert_stmt.bind(1, 42)?;
223    /// assert_eq!(insert_stmt.step()?, State::Done);
224    ///
225    /// query_stmt.reset()?;
226    ///
227    /// while let State::Row = query_stmt.step()? {
228    ///     let id: i64 = query_stmt.read(0)?;
229    ///     assert_eq!(id, 42);
230    /// }
231    /// # Ok::<_, sqlite_ll::Error>(())
232    /// ```
233    #[inline]
234    pub fn prepare(&self, stmt: impl AsRef<str>) -> Result<Statement> {
235        self.prepare_with(stmt, Prepare::EMPTY)
236    }
237
238    /// Build a prepared statement with custom flags.
239    ///
240    /// For long-running statements it is recommended that they have the
241    /// [`Prepare::PERSISTENT`] flag set.
242    ///
243    /// The database connection will be kept open for the lifetime of this
244    /// statement.
245    ///
246    /// # Errors
247    ///
248    /// If the prepare call contains multiple statements, it will error. To
249    /// execute multiple statements, use [`execute`] instead.
250    ///
251    /// ```
252    /// use sqlite_ll::{Connection, Code, Prepare};
253    ///
254    /// let c = Connection::memory()?;
255    ///
256    /// let e = c.prepare_with(
257    ///     "
258    ///     CREATE TABLE test (id INTEGER) /* test */;
259    ///     INSERT INTO test (id) VALUES (1);
260    ///     ",
261    ///     Prepare::PERSISTENT
262    /// ).unwrap_err();
263    /// assert_eq!(e.code(), Code::ERROR);
264    /// # Ok::<_, sqlite_ll::Error>(())
265    /// ```
266    ///
267    /// [`execute`]: Self::execute
268    ///
269    /// # Examples
270    ///
271    /// ```
272    /// use sqlite_ll::{Connection, State, Prepare};
273    ///
274    /// let c = Connection::memory()?;
275    /// c.execute("CREATE TABLE test (id INTEGER);")?;
276    ///
277    /// let mut insert_stmt = c.prepare_with("INSERT INTO test (id) VALUES (?);", Prepare::PERSISTENT)?;
278    /// let mut query_stmt = c.prepare_with("SELECT id FROM test;", Prepare::PERSISTENT)?;
279    ///
280    /// drop(c);
281    ///
282    /// /* .. */
283    ///
284    /// insert_stmt.reset()?;
285    /// insert_stmt.bind(1, 42)?;
286    /// assert_eq!(insert_stmt.step()?, State::Done);
287    ///
288    /// query_stmt.reset()?;
289    ///
290    /// while let State::Row = query_stmt.step()? {
291    ///     let id: i64 = query_stmt.read(0)?;
292    ///     assert_eq!(id, 42);
293    /// }
294    /// # Ok::<_, sqlite_ll::Error>(())
295    /// ```
296    pub fn prepare_with(&self, stmt: impl AsRef<str>, flags: Prepare) -> Result<Statement> {
297        let stmt = stmt.as_ref();
298
299        unsafe {
300            let mut raw = MaybeUninit::uninit();
301            let mut rest = MaybeUninit::uninit();
302
303            let ptr = stmt.as_ptr().cast();
304            let len = i32::try_from(stmt.len()).unwrap_or(i32::MAX);
305
306            sqlite3_try! {
307                ffi::sqlite3_prepare_v3(
308                    self.raw.as_ptr(),
309                    ptr,
310                    len,
311                    flags.0,
312                    raw.as_mut_ptr(),
313                    rest.as_mut_ptr(),
314                )
315            };
316
317            let rest = rest.assume_init();
318
319            let o = rest.offset_from_unsigned(ptr);
320
321            if o != stmt.len() {
322                return Err(Error::new(ffi::SQLITE_ERROR));
323            }
324
325            let raw = ptr::NonNull::new_unchecked(raw.assume_init());
326            Ok(Statement::from_raw(raw))
327        }
328    }
329
330    /// Return the number of rows inserted, updated, or deleted by the most
331    /// recent INSERT, UPDATE, or DELETE statement.
332    #[inline]
333    pub fn change_count(&self) -> usize {
334        unsafe { ffi::sqlite3_changes(self.raw.as_ptr()) as usize }
335    }
336
337    /// Return the total number of rows inserted, updated, and deleted by all
338    /// INSERT, UPDATE, and DELETE statements since the connection was opened.
339    #[inline]
340    pub fn total_change_count(&self) -> usize {
341        unsafe { ffi::sqlite3_total_changes(self.raw.as_ptr()) as usize }
342    }
343
344    /// Set a callback for handling busy events.
345    ///
346    /// The callback is triggered when the database cannot perform an operation
347    /// due to processing of some other request. If the callback returns `true`,
348    /// the operation will be repeated.
349    pub fn set_busy_handler<F>(&mut self, callback: F) -> Result<()>
350    where
351        F: FnMut(usize) -> bool + Send + 'static,
352    {
353        self.remove_busy_handler()?;
354
355        unsafe {
356            let callback = Owned::new(callback)?;
357
358            let result = ffi::sqlite3_busy_handler(
359                self.raw.as_ptr(),
360                Some(busy_callback::<F>),
361                callback.as_ptr().cast(),
362            );
363
364            self.busy_callback = Some(callback);
365            sqlite3_try!(result);
366        }
367
368        Ok(())
369    }
370
371    /// Set an implicit callback for handling busy events that tries to repeat
372    /// rejected operations until a timeout expires.
373    #[inline]
374    pub fn set_busy_timeout(&mut self, ms: c_int) -> Result<()> {
375        unsafe {
376            sqlite3_try! {
377                ffi::sqlite3_busy_timeout(
378                    self.raw.as_ptr(),
379                    ms
380                )
381            };
382        }
383
384        Ok(())
385    }
386
387    /// Remove the callback handling busy events.
388    #[inline]
389    pub fn remove_busy_handler(&mut self) -> Result<()> {
390        unsafe {
391            sqlite3_try! {
392                ffi::sqlite3_busy_handler(
393                    self.raw.as_ptr(),
394                    None,
395                    ptr::null_mut()
396                )
397            };
398        }
399
400        self.busy_callback = None;
401        Ok(())
402    }
403}
404
405impl Drop for Connection {
406    #[inline]
407    #[allow(unused_must_use)]
408    fn drop(&mut self) {
409        self.remove_busy_handler();
410
411        // Will close the connection unconditionally. The database will stay
412        // alive until all associated prepared statements have been closed since
413        // we're using v2.
414        let code = unsafe { ffi::sqlite3_close_v2(self.raw.as_ptr()) };
415        debug_assert_eq!(code, sqlite3_sys::SQLITE_OK);
416    }
417}
418
419/// Options that can be used to customize the opening of a SQLite database.
420#[derive(Default, Clone, Copy, Debug)]
421pub struct OpenOptions {
422    raw: c_int,
423}
424
425impl OpenOptions {
426    /// Create flags for opening a database connection.
427    #[inline]
428    pub fn new() -> Self {
429        Self::default()
430    }
431
432    /// Open a database to the given path.
433    ///
434    /// Note that it is possible to open an in-memory database by passing
435    /// `":memory:"` here, this call might require allocating depending on the
436    /// platform, so it should be avoided in favor of using [`memory`]. To avoid
437    /// allocating for regular paths, you can use [`open_c_str`], however you
438    /// are responsible for ensuring the c-string is a valid path.
439    ///
440    /// [`memory`]: Self::memory
441    /// [`open_c_str`]: Self::open_c_str
442    #[cfg(feature = "std")]
443    #[cfg_attr(docsrs, cfg(feature = "std"))]
444    pub fn open(&self, path: impl AsRef<Path>) -> Result<Connection> {
445        let path = crate::utils::path_to_cstring(path.as_ref())?;
446        self._open(&path)
447    }
448
449    /// Open a database connection with a raw c-string.
450    ///
451    /// This can be used to open in-memory databases by passing `c":memory:"` or
452    /// a regular open call with a filesystem path like
453    /// `c"/path/to/database.sql"`.
454    pub fn open_c_str(&self, name: &CStr) -> Result<Connection> {
455        self._open(name)
456    }
457
458    /// Open an in-memory database.
459    pub fn memory(&self) -> Result<Connection> {
460        self._open(c":memory:")
461    }
462
463    fn _open(&self, name: &CStr) -> Result<Connection> {
464        unsafe {
465            let mut raw = MaybeUninit::uninit();
466
467            let code = ffi::sqlite3_open_v2(name.as_ptr(), raw.as_mut_ptr(), self.raw, ptr::null());
468
469            let raw = raw.assume_init();
470
471            if code != ffi::SQLITE_OK {
472                ffi::sqlite3_close(raw);
473                return Err(Error::new(code));
474            }
475
476            Ok(Connection {
477                raw: NonNull::new_unchecked(raw),
478                busy_callback: None,
479            })
480        }
481    }
482
483    /// Create the database if it does not already exist.
484    pub fn set_create(mut self) -> Self {
485        self.raw |= ffi::SQLITE_OPEN_CREATE;
486        self
487    }
488
489    /// Open the database in the serialized [threading mode][1].
490    ///
491    /// [1]: https://www.sqlite.org/threadsafe.html
492    pub fn set_full_mutex(mut self) -> Self {
493        self.raw |= ffi::SQLITE_OPEN_FULLMUTEX;
494        self
495    }
496
497    /// Opens the database in the multi-thread [threading mode][1].
498    ///
499    /// [1]: https://www.sqlite.org/threadsafe.html
500    pub fn set_no_mutex(mut self) -> Self {
501        self.raw |= ffi::SQLITE_OPEN_NOMUTEX;
502        self
503    }
504
505    /// Open the database for reading only.
506    pub fn set_read_only(mut self) -> Self {
507        self.raw |= ffi::SQLITE_OPEN_READONLY;
508        self
509    }
510
511    /// Open the database for reading and writing.
512    pub fn set_read_write(mut self) -> Self {
513        self.raw |= ffi::SQLITE_OPEN_READWRITE;
514        self
515    }
516}
517
518extern "C" fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int
519where
520    F: FnMut(usize) -> bool,
521{
522    unsafe {
523        if (*(callback as *mut F))(attempts as usize) {
524            1
525        } else {
526            0
527        }
528    }
529}