sqlite_ll/readable.rs
1use core::ffi::c_int;
2use core::ptr;
3
4use alloc::string::String;
5use alloc::vec::Vec;
6
7use sqlite3_sys as ffi;
8
9use crate::{Error, FixedBytes, Null, Result, Statement, Type, Value, Writable};
10
11mod sealed {
12 use alloc::string::String;
13 use alloc::vec::Vec;
14
15 use crate::{FixedBytes, Null, Value};
16
17 pub trait Sealed {}
18 impl Sealed for i64 {}
19 impl Sealed for f64 {}
20 impl Sealed for Null {}
21 impl Sealed for String {}
22 impl Sealed for Vec<u8> {}
23 impl<T> Sealed for Option<T> where T: Sealed {}
24 impl<const N: usize> Sealed for FixedBytes<N> {}
25 impl Sealed for Value {}
26}
27
28/// A type suitable for reading from a prepared statement.
29///
30/// Use with [`Statement::read`].
31pub trait Readable
32where
33 Self: self::sealed::Sealed + Sized,
34{
35 #[doc(hidden)]
36 fn read(stmt: &Statement, index: c_int) -> Result<Self>;
37}
38
39impl Readable for Value {
40 fn read(stmt: &Statement, index: c_int) -> Result<Self> {
41 let value = match stmt.column_type(index) {
42 Type::BLOB => Value::blob(<_>::read(stmt, index)?),
43 Type::TEXT => Value::text(<_>::read(stmt, index)?),
44 Type::FLOAT => Value::float(<_>::read(stmt, index)?),
45 Type::INTEGER => Value::integer(<_>::read(stmt, index)?),
46 Type::NULL => Value::null(),
47 _ => return Err(Error::new(ffi::SQLITE_MISMATCH)),
48 };
49
50 Ok(value)
51 }
52}
53
54/// [`Readable`] implementation for `f64`.
55///
56/// # Examples
57///
58/// ```
59/// use sqlite_ll::{Connection, State};
60///
61/// let c = Connection::memory()?;
62///
63/// c.execute(r##"
64/// CREATE TABLE numbers (value REAL);
65/// INSERT INTO numbers (value) VALUES (3.14), (2.71);
66/// "##)?;
67///
68/// let mut stmt = c.prepare("SELECT value FROM numbers")?;
69///
70/// while let State::Row = stmt.step()? {
71/// let value = stmt.read::<f64>(0)?;
72/// assert!(matches!(value, 3.14 | 2.71));
73/// }
74/// # Ok::<_, sqlite_ll::Error>(())
75/// ```
76impl Readable for f64 {
77 #[inline]
78 fn read(stmt: &Statement, index: c_int) -> Result<Self> {
79 Ok(unsafe { ffi::sqlite3_column_double(stmt.as_ptr(), index) })
80 }
81}
82
83/// [`Readable`] implementation for `i64`.
84///
85/// # Examples
86///
87/// ```
88/// use sqlite_ll::{Connection, State};
89///
90/// let c = Connection::memory()?;
91///
92/// c.execute(r##"
93/// CREATE TABLE numbers (value INTEGER);
94/// INSERT INTO numbers (value) VALUES (3), (2);
95/// "##)?;
96///
97/// let mut stmt = c.prepare("SELECT value FROM numbers")?;
98///
99/// while let State::Row = stmt.step()? {
100/// let value = stmt.read::<i64>(0)?;
101/// assert!(matches!(value, 3 | 2));
102/// }
103/// # Ok::<_, sqlite_ll::Error>(())
104/// ```
105impl Readable for i64 {
106 #[inline]
107 fn read(stmt: &Statement, index: c_int) -> Result<Self> {
108 Ok(unsafe { ffi::sqlite3_column_int64(stmt.as_ptr(), index) })
109 }
110}
111
112/// [`Readable`] implementation which returns a newly allocated [`String`].
113///
114/// For a more memory-efficient way of reading bytes, consider using its
115/// [`Writable`] implementation instead.
116///
117/// # Examples
118///
119/// ```
120/// use sqlite_ll::{Connection, State};
121///
122/// let c = Connection::memory()?;
123///
124/// c.execute(r##"
125/// CREATE TABLE users (name TEXT);
126/// INSERT INTO users (name) VALUES ('Alice'), ('Bob');
127/// "##)?;
128///
129/// let mut stmt = c.prepare("SELECT name FROM users")?;
130///
131/// while let State::Row = stmt.step()? {
132/// let name = stmt.read::<String>(0)?;
133/// assert!(matches!(name.as_str(), "Alice" | "Bob"));
134/// }
135/// # Ok::<_, sqlite_ll::Error>(())
136/// ```
137///
138/// Automatic conversion:
139///
140/// ```
141/// use sqlite_ll::{Connection, State};
142///
143/// let c = Connection::memory()?;
144///
145/// c.execute(r##"
146/// CREATE TABLE users (id INTEGER);
147/// INSERT INTO users (id) VALUES (1), (2);
148/// "##)?;
149///
150/// let mut stmt = c.prepare("SELECT id FROM users")?;
151///
152/// while let State::Row = stmt.step()? {
153/// let name = stmt.read::<String>(0)?;
154/// assert!(matches!(name.as_str(), "1" | "2"));
155/// }
156/// # Ok::<_, sqlite_ll::Error>(())
157/// ```
158impl Readable for String {
159 #[inline]
160 fn read(stmt: &Statement, index: c_int) -> Result<Self> {
161 let mut s = String::new();
162 s.write(stmt, index)?;
163 Ok(s)
164 }
165}
166
167/// [`Readable`] implementation which returns a newly allocated [`Vec`].
168///
169/// For a more memory-efficient way of reading bytes, consider using its
170/// [`Writable`] implementation instead.
171///
172/// # Examples
173///
174/// ```
175/// use sqlite_ll::{Connection, State};
176///
177/// let c = Connection::memory()?;
178///
179/// c.execute(r##"
180/// CREATE TABLE users (name TEXT);
181/// INSERT INTO users (name) VALUES ('Alice'), ('Bob');
182/// "##)?;
183///
184/// let mut stmt = c.prepare("SELECT name FROM users")?;
185///
186/// while let State::Row = stmt.step()? {
187/// let name = stmt.read::<Vec<u8>>(0)?;
188/// assert!(matches!(name.as_slice(), b"Alice" | b"Bob"));
189/// }
190/// # Ok::<_, sqlite_ll::Error>(())
191/// ```
192///
193/// Automatic conversion:
194///
195/// ```
196/// use sqlite_ll::{Connection, State};
197///
198/// let c = Connection::memory()?;
199///
200/// c.execute(r##"
201/// CREATE TABLE users (id INTEGER);
202/// INSERT INTO users (id) VALUES (1), (2);
203/// "##)?;
204///
205/// let mut stmt = c.prepare("SELECT id FROM users")?;
206///
207/// while let State::Row = stmt.step()? {
208/// let name = stmt.read::<Vec::<u8>>(0)?;
209/// assert!(matches!(name.as_slice(), b"1" | b"2"));
210/// }
211/// # Ok::<_, sqlite_ll::Error>(())
212/// ```
213impl Readable for Vec<u8> {
214 #[inline]
215 fn read(stmt: &Statement, index: c_int) -> Result<Self> {
216 let mut buf = Vec::new();
217 buf.write(stmt, index)?;
218 Ok(buf)
219 }
220}
221
222/// [`Readable`] implementation for [`FixedBytes`] which reads at most `N`
223/// bytes.
224///
225/// If the column contains more than `N` bytes, a [`Code::MISMATCH`] error is
226/// returned.
227///
228/// # Examples
229///
230/// ```
231/// use sqlite_ll::{Connection, State, FixedBytes, Code};
232///
233/// let c = Connection::memory()?;
234/// c.execute(r##"
235/// CREATE TABLE users (id BLOB);
236/// INSERT INTO users (id) VALUES (X'01020304'), (X'0506070809');
237/// "##)?;
238///
239/// let mut stmt = c.prepare("SELECT id FROM users")?;
240///
241/// assert_eq!(stmt.step()?, State::Row);
242/// let bytes = stmt.read::<FixedBytes<4>>(0)?;
243/// assert_eq!(bytes.as_bytes(), &[1, 2, 3, 4]);
244///
245/// assert_eq!(stmt.step()?, State::Row);
246/// let e = stmt.read::<FixedBytes<4>>(0).unwrap_err();
247/// assert_eq!(e.code(), Code::MISMATCH);
248///
249/// let bytes = stmt.read::<FixedBytes<5>>(0)?;
250/// assert_eq!(bytes.as_bytes(), &[5, 6, 7, 8, 9]);
251/// # Ok::<_, sqlite_ll::Error>(())
252/// ```
253impl<const N: usize> Readable for FixedBytes<N> {
254 #[inline]
255 fn read(stmt: &Statement, index: c_int) -> Result<Self> {
256 let mut bytes = FixedBytes::new();
257
258 unsafe {
259 let ptr = ffi::sqlite3_column_blob(stmt.as_ptr(), index);
260
261 if ptr.is_null() {
262 return Ok(bytes);
263 }
264
265 let Ok(len) = usize::try_from(ffi::sqlite3_column_bytes(stmt.as_ptr(), index)) else {
266 return Err(Error::new(ffi::SQLITE_MISMATCH));
267 };
268
269 if len > N {
270 return Err(Error::new(ffi::SQLITE_MISMATCH));
271 }
272
273 ptr::copy_nonoverlapping(ptr.cast::<u8>(), bytes.as_mut_ptr(), len);
274
275 bytes.set_len(len);
276 Ok(bytes)
277 }
278 }
279}
280
281/// [`Readable`] implementation for [`Null`].
282///
283/// # Examples
284///
285/// ```
286/// use sqlite_ll::{Connection, Null, State};
287///
288/// let c = Connection::memory()?;
289/// c.execute(r##"
290/// CREATE TABLE users (name TEXT, age INTEGER);
291/// INSERT INTO users (name, age) VALUES ('Alice', NULL), ('Bob', 30);
292/// "##)?;
293///
294/// let mut stmt = c.prepare("SELECT age FROM users WHERE name = ?")?;
295/// stmt.bind(1, "Alice")?;
296///
297/// let mut names = Vec::new();
298///
299/// while let State::Row = stmt.step()? {
300/// names.push(stmt.read::<Null>(0)?);
301/// }
302///
303/// assert_eq!(names, vec![Null]);
304/// # Ok::<_, sqlite_ll::Error>(())
305/// ```
306impl Readable for Null {
307 #[inline]
308 fn read(stmt: &Statement, index: c_int) -> Result<Self> {
309 if stmt.column_type(index) == Type::NULL {
310 Ok(Null)
311 } else {
312 Err(Error::new(ffi::SQLITE_MISMATCH))
313 }
314 }
315}
316
317/// [`Readable`] implementation for [`Option`].
318///
319/// # Examples
320///
321/// ```
322/// use sqlite_ll::{Connection, State};
323///
324/// let c = Connection::memory()?;
325/// c.execute(r##"
326/// CREATE TABLE users (name TEXT, age INTEGER);
327/// "##)?;
328///
329/// let mut stmt = c.prepare("INSERT INTO users (name, age) VALUES (?, ?)")?;
330///
331/// stmt.reset()?;
332/// stmt.bind(1, "Alice")?;
333/// stmt.bind(2, None::<i64>)?;
334/// assert_eq!(stmt.step()?, State::Done);
335///
336/// stmt.reset()?;
337/// stmt.bind(1, "Bob")?;
338/// stmt.bind(2, Some(30i64))?;
339/// assert_eq!(stmt.step()?, State::Done);
340///
341/// let mut stmt = c.prepare("SELECT name, age FROM users")?;
342///
343/// let mut names_and_ages = Vec::new();
344///
345/// while let State::Row = stmt.step()? {
346/// let name: String = stmt.read(0)?;
347/// let age: Option<i64> = stmt.read(1)?;
348/// names_and_ages.push((name, age));
349/// }
350///
351/// names_and_ages.sort();
352/// assert_eq!(names_and_ages, vec![(String::from("Alice"), None), (String::from("Bob"), Some(30))]);
353/// # Ok::<_, sqlite_ll::Error>(())
354/// ```
355impl<T> Readable for Option<T>
356where
357 T: Readable,
358{
359 #[inline]
360 fn read(stmt: &Statement, index: c_int) -> Result<Self> {
361 if stmt.column_type(index) == Type::NULL {
362 Ok(None)
363 } else {
364 T::read(stmt, index).map(Some)
365 }
366 }
367}