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}