sqlite_ll/
bindable.rs

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