Skip to main content

sqlite_provider/connection/
core.rs

1use core::ptr::NonNull;
2
3use crate::error::{Error, Result};
4use crate::provider::{FeatureSet, OpenOptions, Sqlite3Api, Sqlite3Keying};
5use crate::statement::Statement;
6
7/// Safe wrapper around a `sqlite3*` connection.
8pub struct Connection<'p, P: Sqlite3Api> {
9    pub(crate) api: &'p P,
10    pub(crate) db: NonNull<P::Db>,
11}
12
13impl<'p, P: Sqlite3Api> Connection<'p, P> {
14    /// Open a connection using the provider SPI.
15    pub fn open(api: &'p P, filename: &str, options: OpenOptions<'_>) -> Result<Self> {
16        let db = unsafe { api.open(filename, options)? };
17        Ok(Self { api, db })
18    }
19
20    /// Prepare a statement, using prepare_v3 when available.
21    pub fn prepare(&self, sql: &str) -> Result<Statement<'_, 'p, P>> {
22        let stmt = unsafe {
23            if self.api.feature_set().contains(FeatureSet::PREPARE_V3) {
24                self.api.prepare_v3(self.db, sql, 0)?
25            } else {
26                self.api.prepare_v2(self.db, sql)?
27            }
28        };
29        Ok(Statement::new(self, stmt))
30    }
31
32    /// Prepare a statement with flags (requires prepare_v3 support).
33    pub fn prepare_with_flags(&self, sql: &str, flags: u32) -> Result<Statement<'_, 'p, P>> {
34        if !self.api.feature_set().contains(FeatureSet::PREPARE_V3) {
35            return Err(Error::feature_unavailable("prepare_v3 unsupported"));
36        }
37        let stmt = unsafe { self.api.prepare_v3(self.db, sql, flags)? };
38        Ok(Statement::new(self, stmt))
39    }
40
41    /// Expose the raw database handle.
42    pub fn raw_handle(&self) -> NonNull<P::Db> {
43        self.db
44    }
45}
46
47impl<'p, P: Sqlite3Keying> Connection<'p, P> {
48    /// Open a connection and immediately apply a key (SQLCipher-style).
49    pub fn open_with_key(
50        api: &'p P,
51        filename: &str,
52        options: OpenOptions<'_>,
53        key: &[u8],
54    ) -> Result<Self> {
55        let db = unsafe { api.open(filename, options)? };
56        if let Err(err) = unsafe { api.key(db, key) } {
57            let _ = unsafe { api.close(db) };
58            return Err(err);
59        }
60        Ok(Self { api, db })
61    }
62
63    /// Rekey the database (SQLCipher-style).
64    pub fn rekey(&self, key: &[u8]) -> Result<()> {
65        unsafe { self.api.rekey(self.db, key) }
66    }
67}
68
69impl<'p, P: Sqlite3Api> Drop for Connection<'p, P> {
70    fn drop(&mut self) {
71        let _ = unsafe { self.api.close(self.db) };
72    }
73}