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