diesel/sqlite/connection/
bind_collector.rs

1use crate::query_builder::{BindCollector, MoveableBindCollector};
2use crate::serialize::{IsNull, Output};
3use crate::sql_types::HasSqlType;
4use crate::sqlite::{Sqlite, SqliteType};
5use crate::QueryResult;
6#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
7use libsqlite3_sys as ffi;
8#[cfg(all(target_family = "wasm", target_os = "unknown"))]
9use sqlite_wasm_rs::export as ffi;
10
11#[derive(Debug, Default)]
12pub struct SqliteBindCollector<'a> {
13    pub(in crate::sqlite) binds: Vec<(InternalSqliteBindValue<'a>, SqliteType)>,
14}
15
16impl SqliteBindCollector<'_> {
17    pub(in crate::sqlite) fn new() -> Self {
18        Self { binds: Vec::new() }
19    }
20}
21
22/// This type represents a value bound to
23/// a sqlite prepared statement
24///
25/// It can be constructed via the various `From<T>` implementations
26#[derive(Debug)]
27pub struct SqliteBindValue<'a> {
28    pub(in crate::sqlite) inner: InternalSqliteBindValue<'a>,
29}
30
31impl From<i32> for SqliteBindValue<'_> {
32    fn from(i: i32) -> Self {
33        Self {
34            inner: InternalSqliteBindValue::I32(i),
35        }
36    }
37}
38
39impl From<i64> for SqliteBindValue<'_> {
40    fn from(i: i64) -> Self {
41        Self {
42            inner: InternalSqliteBindValue::I64(i),
43        }
44    }
45}
46
47impl From<f64> for SqliteBindValue<'_> {
48    fn from(f: f64) -> Self {
49        Self {
50            inner: InternalSqliteBindValue::F64(f),
51        }
52    }
53}
54
55impl<'a, T> From<Option<T>> for SqliteBindValue<'a>
56where
57    T: Into<SqliteBindValue<'a>>,
58{
59    fn from(o: Option<T>) -> Self {
60        match o {
61            Some(v) => v.into(),
62            None => Self {
63                inner: InternalSqliteBindValue::Null,
64            },
65        }
66    }
67}
68
69impl<'a> From<&'a str> for SqliteBindValue<'a> {
70    fn from(s: &'a str) -> Self {
71        Self {
72            inner: InternalSqliteBindValue::BorrowedString(s),
73        }
74    }
75}
76
77impl From<String> for SqliteBindValue<'_> {
78    fn from(s: String) -> Self {
79        Self {
80            inner: InternalSqliteBindValue::String(s.into_boxed_str()),
81        }
82    }
83}
84
85impl From<Vec<u8>> for SqliteBindValue<'_> {
86    fn from(b: Vec<u8>) -> Self {
87        Self {
88            inner: InternalSqliteBindValue::Binary(b.into_boxed_slice()),
89        }
90    }
91}
92
93impl<'a> From<&'a [u8]> for SqliteBindValue<'a> {
94    fn from(b: &'a [u8]) -> Self {
95        Self {
96            inner: InternalSqliteBindValue::BorrowedBinary(b),
97        }
98    }
99}
100
101#[derive(Debug)]
102pub(crate) enum InternalSqliteBindValue<'a> {
103    BorrowedString(&'a str),
104    String(Box<str>),
105    BorrowedBinary(&'a [u8]),
106    Binary(Box<[u8]>),
107    I32(i32),
108    I64(i64),
109    F64(f64),
110    Null,
111}
112
113impl std::fmt::Display for InternalSqliteBindValue<'_> {
114    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115        let n = match self {
116            InternalSqliteBindValue::BorrowedString(_) | InternalSqliteBindValue::String(_) => {
117                "Text"
118            }
119            InternalSqliteBindValue::BorrowedBinary(_) | InternalSqliteBindValue::Binary(_) => {
120                "Binary"
121            }
122            InternalSqliteBindValue::I32(_) | InternalSqliteBindValue::I64(_) => "Integer",
123            InternalSqliteBindValue::F64(_) => "Float",
124            InternalSqliteBindValue::Null => "Null",
125        };
126        f.write_str(n)
127    }
128}
129
130impl InternalSqliteBindValue<'_> {
131    #[allow(unsafe_code)] // ffi function calls
132    pub(in crate::sqlite) fn result_of(
133        self,
134        ctx: &mut ffi::sqlite3_context,
135    ) -> Result<(), std::num::TryFromIntError> {
136        use std::os::raw as libc;
137        // This unsafe block assumes the following invariants:
138        //
139        // - `ctx` points to valid memory
140        unsafe {
141            match self {
142                InternalSqliteBindValue::BorrowedString(s) => ffi::sqlite3_result_text(
143                    ctx,
144                    s.as_ptr() as *const libc::c_char,
145                    s.len().try_into()?,
146                    ffi::SQLITE_TRANSIENT(),
147                ),
148                InternalSqliteBindValue::String(s) => ffi::sqlite3_result_text(
149                    ctx,
150                    s.as_ptr() as *const libc::c_char,
151                    s.len().try_into()?,
152                    ffi::SQLITE_TRANSIENT(),
153                ),
154                InternalSqliteBindValue::Binary(b) => ffi::sqlite3_result_blob(
155                    ctx,
156                    b.as_ptr() as *const libc::c_void,
157                    b.len().try_into()?,
158                    ffi::SQLITE_TRANSIENT(),
159                ),
160                InternalSqliteBindValue::BorrowedBinary(b) => ffi::sqlite3_result_blob(
161                    ctx,
162                    b.as_ptr() as *const libc::c_void,
163                    b.len().try_into()?,
164                    ffi::SQLITE_TRANSIENT(),
165                ),
166                InternalSqliteBindValue::I32(i) => ffi::sqlite3_result_int(ctx, i as libc::c_int),
167                InternalSqliteBindValue::I64(l) => ffi::sqlite3_result_int64(ctx, l),
168                InternalSqliteBindValue::F64(d) => {
169                    ffi::sqlite3_result_double(ctx, d as libc::c_double)
170                }
171                InternalSqliteBindValue::Null => ffi::sqlite3_result_null(ctx),
172            }
173        }
174        Ok(())
175    }
176}
177
178impl<'a> BindCollector<'a, Sqlite> for SqliteBindCollector<'a> {
179    type Buffer = SqliteBindValue<'a>;
180
181    fn push_bound_value<T, U>(&mut self, bind: &'a U, metadata_lookup: &mut ()) -> QueryResult<()>
182    where
183        Sqlite: crate::sql_types::HasSqlType<T>,
184        U: crate::serialize::ToSql<T, Sqlite> + ?Sized,
185    {
186        let value = SqliteBindValue {
187            inner: InternalSqliteBindValue::Null,
188        };
189        let mut to_sql_output = Output::new(value, metadata_lookup);
190        let is_null = bind
191            .to_sql(&mut to_sql_output)
192            .map_err(crate::result::Error::SerializationError)?;
193        let bind = to_sql_output.into_inner();
194        let metadata = Sqlite::metadata(metadata_lookup);
195        self.binds.push((
196            match is_null {
197                IsNull::No => bind.inner,
198                IsNull::Yes => InternalSqliteBindValue::Null,
199            },
200            metadata,
201        ));
202        Ok(())
203    }
204
205    fn push_null_value(&mut self, metadata: SqliteType) -> QueryResult<()> {
206        self.binds.push((InternalSqliteBindValue::Null, metadata));
207        Ok(())
208    }
209}
210
211#[derive(Debug)]
212enum OwnedSqliteBindValue {
213    String(Box<str>),
214    Binary(Box<[u8]>),
215    I32(i32),
216    I64(i64),
217    F64(f64),
218    Null,
219}
220
221impl<'a> std::convert::From<&InternalSqliteBindValue<'a>> for OwnedSqliteBindValue {
222    fn from(value: &InternalSqliteBindValue<'a>) -> Self {
223        match value {
224            InternalSqliteBindValue::String(s) => Self::String(s.clone()),
225            InternalSqliteBindValue::BorrowedString(s) => {
226                Self::String(String::from(*s).into_boxed_str())
227            }
228            InternalSqliteBindValue::Binary(b) => Self::Binary(b.clone()),
229            InternalSqliteBindValue::BorrowedBinary(s) => {
230                Self::Binary(Vec::from(*s).into_boxed_slice())
231            }
232            InternalSqliteBindValue::I32(val) => Self::I32(*val),
233            InternalSqliteBindValue::I64(val) => Self::I64(*val),
234            InternalSqliteBindValue::F64(val) => Self::F64(*val),
235            InternalSqliteBindValue::Null => Self::Null,
236        }
237    }
238}
239
240impl std::convert::From<&OwnedSqliteBindValue> for InternalSqliteBindValue<'_> {
241    fn from(value: &OwnedSqliteBindValue) -> Self {
242        match value {
243            OwnedSqliteBindValue::String(s) => Self::String(s.clone()),
244            OwnedSqliteBindValue::Binary(b) => Self::Binary(b.clone()),
245            OwnedSqliteBindValue::I32(val) => Self::I32(*val),
246            OwnedSqliteBindValue::I64(val) => Self::I64(*val),
247            OwnedSqliteBindValue::F64(val) => Self::F64(*val),
248            OwnedSqliteBindValue::Null => Self::Null,
249        }
250    }
251}
252
253#[derive(Debug)]
254/// Sqlite bind collector data that is movable across threads
255pub struct SqliteBindCollectorData {
256    binds: Vec<(OwnedSqliteBindValue, SqliteType)>,
257}
258
259impl MoveableBindCollector<Sqlite> for SqliteBindCollector<'_> {
260    type BindData = SqliteBindCollectorData;
261
262    fn moveable(&self) -> Self::BindData {
263        let mut binds = Vec::with_capacity(self.binds.len());
264        for b in self
265            .binds
266            .iter()
267            .map(|(bind, tpe)| (OwnedSqliteBindValue::from(bind), *tpe))
268        {
269            binds.push(b);
270        }
271        SqliteBindCollectorData { binds }
272    }
273
274    fn append_bind_data(&mut self, from: &Self::BindData) {
275        self.binds.reserve_exact(from.binds.len());
276        self.binds.extend(
277            from.binds
278                .iter()
279                .map(|(bind, tpe)| (InternalSqliteBindValue::from(bind), *tpe)),
280        );
281    }
282}