Skip to main content

sqlite_provider/connection/
extensions.rs

1use core::marker::PhantomData;
2use core::ptr::NonNull;
3
4use crate::error::Result;
5use crate::provider::{
6    ColumnMetadata, OwnedBytes, RawBytes, Sqlite3Backup, Sqlite3BlobIo, Sqlite3Metadata,
7    Sqlite3Serialize, Sqlite3Wal,
8};
9use crate::statement::Statement;
10
11use super::core::Connection;
12
13/// RAII wrapper around an online backup handle.
14///
15/// The handle borrows both source and destination connections used to create
16/// it, preventing use after either connection is closed.
17pub struct Backup<'c, 'p, P: Sqlite3Backup> {
18    api: &'p P,
19    handle: NonNull<P::Backup>,
20    _conn: PhantomData<&'c Connection<'p, P>>,
21}
22
23impl<'c, 'p, P: Sqlite3Backup> Backup<'c, 'p, P> {
24    /// Copy up to `pages` pages.
25    pub fn step(&self, pages: i32) -> Result<()> {
26        unsafe { self.api.backup_step(self.handle, pages) }
27    }
28
29    /// Remaining pages in the backup.
30    pub fn remaining(&self) -> i32 {
31        unsafe { self.api.backup_remaining(self.handle) }
32    }
33
34    /// Total page count in the backup.
35    pub fn pagecount(&self) -> i32 {
36        unsafe { self.api.backup_pagecount(self.handle) }
37    }
38}
39
40impl<'c, 'p, P: Sqlite3Backup> Drop for Backup<'c, 'p, P> {
41    fn drop(&mut self) {
42        let _ = unsafe { self.api.backup_finish(self.handle) };
43    }
44}
45
46impl<'p, P: Sqlite3Backup> Connection<'p, P> {
47    /// Start a backup from this database to `dest`.
48    pub fn backup_to<'c>(
49        &'c self,
50        dest: &'c Connection<'p, P>,
51        name: &str,
52    ) -> Result<Backup<'c, 'p, P>> {
53        let handle = unsafe { self.api.backup_init(dest.db, name, self.db, "main")? };
54        Ok(Backup {
55            api: self.api,
56            handle,
57            _conn: PhantomData,
58        })
59    }
60}
61
62/// RAII wrapper around an incremental blob handle.
63///
64/// The handle borrows the originating connection so blob operations cannot
65/// outlive the database handle.
66pub struct Blob<'c, 'p, P: Sqlite3BlobIo> {
67    api: &'p P,
68    handle: NonNull<P::Blob>,
69    _conn: PhantomData<&'c Connection<'p, P>>,
70}
71
72impl<'c, 'p, P: Sqlite3BlobIo> Blob<'c, 'p, P> {
73    /// Read from the blob into `buf` at `offset`.
74    pub fn read(&self, buf: &mut [u8], offset: i32) -> Result<()> {
75        unsafe { self.api.blob_read(self.handle, buf, offset) }
76    }
77
78    /// Write `buf` into the blob at `offset`.
79    pub fn write(&self, buf: &[u8], offset: i32) -> Result<()> {
80        unsafe { self.api.blob_write(self.handle, buf, offset) }
81    }
82
83    /// Blob size in bytes.
84    pub fn len(&self) -> i32 {
85        unsafe { self.api.blob_bytes(self.handle) }
86    }
87
88    /// Whether the blob has zero length.
89    pub fn is_empty(&self) -> bool {
90        self.len() == 0
91    }
92}
93
94impl<'c, 'p, P: Sqlite3BlobIo> Drop for Blob<'c, 'p, P> {
95    fn drop(&mut self) {
96        let _ = unsafe { self.api.blob_close(self.handle) };
97    }
98}
99
100impl<'p, P: Sqlite3BlobIo> Connection<'p, P> {
101    /// Open an incremental blob handle.
102    pub fn open_blob<'c>(
103        &'c self,
104        db_name: &str,
105        table: &str,
106        column: &str,
107        rowid: i64,
108        flags: u32,
109    ) -> Result<Blob<'c, 'p, P>> {
110        let handle = unsafe {
111            self.api
112                .blob_open(self.db, db_name, table, column, rowid, flags)?
113        };
114        Ok(Blob {
115            api: self.api,
116            handle,
117            _conn: PhantomData,
118        })
119    }
120}
121
122/// Serialized database buffer owned by the backend.
123pub struct SerializedDb<'p, P: Sqlite3Serialize> {
124    api: &'p P,
125    bytes: OwnedBytes,
126}
127
128impl<'p, P: Sqlite3Serialize> SerializedDb<'p, P> {
129    /// View the serialized bytes.
130    pub fn as_slice(&self) -> &[u8] {
131        unsafe { core::slice::from_raw_parts(self.bytes.ptr.as_ptr(), self.bytes.len) }
132    }
133
134    /// Copy the bytes into a Vec and free the backend buffer.
135    pub fn into_vec(self) -> Vec<u8> {
136        let me = core::mem::ManuallyDrop::new(self);
137        let vec = me.as_slice().to_vec();
138        unsafe { Sqlite3Serialize::free(me.api, me.bytes) };
139        vec
140    }
141}
142
143impl<'p, P: Sqlite3Serialize> Drop for SerializedDb<'p, P> {
144    fn drop(&mut self) {
145        unsafe { Sqlite3Serialize::free(self.api, self.bytes) };
146    }
147}
148
149impl<'p, P: Sqlite3Serialize> Connection<'p, P> {
150    /// Serialize the database into an owned buffer.
151    pub fn serialize(&self, schema: Option<&str>, flags: u32) -> Result<SerializedDb<'p, P>> {
152        let bytes = unsafe { self.api.serialize(self.db, schema, flags)? };
153        Ok(SerializedDb {
154            api: self.api,
155            bytes,
156        })
157    }
158
159    /// Deserialize bytes into the database.
160    pub fn deserialize(&self, schema: Option<&str>, data: &[u8], flags: u32) -> Result<()> {
161        unsafe { self.api.deserialize(self.db, schema, data, flags) }
162    }
163}
164
165impl<'p, P: Sqlite3Wal> Connection<'p, P> {
166    /// Run a WAL checkpoint.
167    pub fn wal_checkpoint(&self, db_name: Option<&str>) -> Result<()> {
168        unsafe { self.api.wal_checkpoint(self.db, db_name) }
169    }
170
171    /// Run a WAL checkpoint with a mode, returning (log, checkpointed) page counts.
172    pub fn wal_checkpoint_v2(&self, db_name: Option<&str>, mode: i32) -> Result<(i32, i32)> {
173        unsafe { self.api.wal_checkpoint_v2(self.db, db_name, mode) }
174    }
175
176    /// Return libsql WAL frame count if supported.
177    pub fn wal_frame_count(&self) -> Result<Option<u32>> {
178        unsafe { self.api.wal_frame_count(self.db) }
179    }
180}
181
182impl<'p, P: Sqlite3Metadata> Connection<'p, P> {
183    /// Fetch column metadata for a table.
184    pub fn table_column_metadata(
185        &self,
186        db_name: Option<&str>,
187        table: &str,
188        column: &str,
189    ) -> Result<ColumnMetadata> {
190        unsafe {
191            self.api
192                .table_column_metadata(self.db, db_name, table, column)
193        }
194    }
195}
196
197impl<'p, P: Sqlite3Metadata> Statement<'_, 'p, P> {
198    /// Raw declared column type.
199    pub fn column_decltype_raw(&self, col: i32) -> Option<RawBytes> {
200        unsafe { self.conn.api.column_decltype(self.stmt, col) }
201    }
202
203    /// Raw column name.
204    pub fn column_name_raw(&self, col: i32) -> Option<RawBytes> {
205        unsafe { self.conn.api.column_name(self.stmt, col) }
206    }
207
208    /// Raw column table name.
209    pub fn column_table_name_raw(&self, col: i32) -> Option<RawBytes> {
210        unsafe { self.conn.api.column_table_name(self.stmt, col) }
211    }
212}