1use crate::QueryResult;
2use crate::query_builder::{BindCollector, MoveableBindCollector};
3use crate::serialize::{IsNull, Output};
4use crate::sql_types::HasSqlType;
5use crate::sqlite::{Sqlite, SqliteType};
6use alloc::boxed::Box;
7use alloc::string::String;
8use alloc::vec::Vec;
9#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
10use libsqlite3_sys as ffi;
11#[cfg(all(target_family = "wasm", target_os = "unknown"))]
12use sqlite_wasm_rs as ffi;
13
14#[derive(#[automatically_derived]
impl<'a> ::core::fmt::Debug for SqliteBindCollector<'a> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"SqliteBindCollector", "binds", &&self.binds)
}
}Debug, #[automatically_derived]
impl<'a> ::core::default::Default for SqliteBindCollector<'a> {
#[inline]
fn default() -> SqliteBindCollector<'a> {
SqliteBindCollector { binds: ::core::default::Default::default() }
}
}Default)]
18pub struct SqliteBindCollector<'a> {
19 pub(in crate::sqlite) binds: Vec<(SqliteBindValueRef<'a>, SqliteType)>,
20}
21
22impl<'a> SqliteBindCollector<'a> {
23 #[doc = " Construct an empty `SqliteBindCollector`"]
pub fn new() -> Self { Self { binds: Vec::new() } }#[diesel_derives::__diesel_public_if(
25 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
26 )]
27 pub(in crate::sqlite) fn new() -> Self {
28 Self { binds: Vec::new() }
29 }
30
31 #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
79 pub fn binds(&self) -> impl ExactSizeIterator<Item = (&SqliteBindValueRef<'a>, SqliteType)> {
80 self.binds.iter().map(|(v, t)| (v, *t))
81 }
82}
83
84#[derive(#[automatically_derived]
impl<'a> ::core::fmt::Debug for SqliteBindValue<'a> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"SqliteBindValue", "inner", &&self.inner)
}
}Debug)]
89pub struct SqliteBindValue<'a> {
90 pub(in crate::sqlite) inner: SqliteBindValueRef<'a>,
91}
92
93impl From<i32> for SqliteBindValue<'_> {
94 fn from(i: i32) -> Self {
95 Self {
96 inner: SqliteBindValueRef::I32(i),
97 }
98 }
99}
100
101impl From<i64> for SqliteBindValue<'_> {
102 fn from(i: i64) -> Self {
103 Self {
104 inner: SqliteBindValueRef::I64(i),
105 }
106 }
107}
108
109impl From<f64> for SqliteBindValue<'_> {
110 fn from(f: f64) -> Self {
111 Self {
112 inner: SqliteBindValueRef::F64(f),
113 }
114 }
115}
116
117impl<'a, T> From<Option<T>> for SqliteBindValue<'a>
118where
119 T: Into<SqliteBindValue<'a>>,
120{
121 fn from(o: Option<T>) -> Self {
122 match o {
123 Some(v) => v.into(),
124 None => Self {
125 inner: SqliteBindValueRef::Null,
126 },
127 }
128 }
129}
130
131impl<'a> From<&'a str> for SqliteBindValue<'a> {
132 fn from(s: &'a str) -> Self {
133 Self {
134 inner: SqliteBindValueRef::BorrowedString(s),
135 }
136 }
137}
138
139impl From<String> for SqliteBindValue<'_> {
140 fn from(s: String) -> Self {
141 Self {
142 inner: SqliteBindValueRef::String(s.into_boxed_str()),
143 }
144 }
145}
146
147impl From<Vec<u8>> for SqliteBindValue<'_> {
148 fn from(b: Vec<u8>) -> Self {
149 Self {
150 inner: SqliteBindValueRef::Binary(b.into_boxed_slice()),
151 }
152 }
153}
154
155impl<'a> From<&'a [u8]> for SqliteBindValue<'a> {
156 fn from(b: &'a [u8]) -> Self {
157 Self {
158 inner: SqliteBindValueRef::BorrowedBinary(b),
159 }
160 }
161}
162
163#[derive(#[automatically_derived]
impl<'a> ::core::fmt::Debug for SqliteBindValueRef<'a> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
SqliteBindValueRef::BorrowedString(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"BorrowedString", &__self_0),
SqliteBindValueRef::String(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "String",
&__self_0),
SqliteBindValueRef::BorrowedBinary(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"BorrowedBinary", &__self_0),
SqliteBindValueRef::Binary(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Binary",
&__self_0),
SqliteBindValueRef::I32(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "I32",
&__self_0),
SqliteBindValueRef::I64(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "I64",
&__self_0),
SqliteBindValueRef::F64(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "F64",
&__self_0),
SqliteBindValueRef::Null =>
::core::fmt::Formatter::write_str(f, "Null"),
}
}
}Debug)]
170#[doc = " The concrete bind value carried by a live [`SqliteBindCollector`]."]
#[doc = ""]
#[doc =
" Distinct from [`OwnedSqliteBindValue`] (the moved snapshot stored in"]
#[doc =
" [`SqliteBindCollectorData`]) in that borrowed and owned string or blob"]
#[doc =
" variants are kept separate, which lets third-party backends read the"]
#[doc = " collector without cloning transient buffers."]
pub enum SqliteBindValueRef<'a> {
BorrowedString(&'a str),
String(Box<str>),
BorrowedBinary(&'a [u8]),
Binary(Box<[u8]>),
I32(i32),
I64(i64),
F64(f64),
Null,
}#[diesel_derives::__diesel_public_if(
171 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
172)]
173pub(crate) enum SqliteBindValueRef<'a> {
174 BorrowedString(&'a str),
176 String(Box<str>),
178 BorrowedBinary(&'a [u8]),
180 Binary(Box<[u8]>),
182 I32(i32),
184 I64(i64),
186 F64(f64),
188 Null,
190}
191
192impl core::fmt::Display for SqliteBindValueRef<'_> {
193 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
194 let n = match self {
195 SqliteBindValueRef::BorrowedString(_) | SqliteBindValueRef::String(_) => "Text",
196 SqliteBindValueRef::BorrowedBinary(_) | SqliteBindValueRef::Binary(_) => "Binary",
197 SqliteBindValueRef::I32(_) | SqliteBindValueRef::I64(_) => "Integer",
198 SqliteBindValueRef::F64(_) => "Float",
199 SqliteBindValueRef::Null => "Null",
200 };
201 f.write_str(n)
202 }
203}
204
205impl SqliteBindValueRef<'_> {
206 #[allow(unsafe_code)] pub(in crate::sqlite) fn result_of(
208 self,
209 ctx: &mut ffi::sqlite3_context,
210 ) -> Result<(), core::num::TryFromIntError> {
211 use core::ffi as libc;
212 unsafe {
216 match self {
217 SqliteBindValueRef::BorrowedString(s) => ffi::sqlite3_result_text(
218 ctx,
219 s.as_ptr() as *const libc::c_char,
220 s.len().try_into()?,
221 ffi::SQLITE_TRANSIENT(),
222 ),
223 SqliteBindValueRef::String(s) => ffi::sqlite3_result_text(
224 ctx,
225 s.as_ptr() as *const libc::c_char,
226 s.len().try_into()?,
227 ffi::SQLITE_TRANSIENT(),
228 ),
229 SqliteBindValueRef::Binary(b) => ffi::sqlite3_result_blob(
230 ctx,
231 b.as_ptr() as *const libc::c_void,
232 b.len().try_into()?,
233 ffi::SQLITE_TRANSIENT(),
234 ),
235 SqliteBindValueRef::BorrowedBinary(b) => ffi::sqlite3_result_blob(
236 ctx,
237 b.as_ptr() as *const libc::c_void,
238 b.len().try_into()?,
239 ffi::SQLITE_TRANSIENT(),
240 ),
241 SqliteBindValueRef::I32(i) => ffi::sqlite3_result_int(ctx, i as libc::c_int),
242 SqliteBindValueRef::I64(l) => ffi::sqlite3_result_int64(ctx, l),
243 SqliteBindValueRef::F64(d) => ffi::sqlite3_result_double(ctx, d as libc::c_double),
244 SqliteBindValueRef::Null => ffi::sqlite3_result_null(ctx),
245 }
246 }
247 Ok(())
248 }
249}
250
251impl<'a> BindCollector<'a, Sqlite> for SqliteBindCollector<'a> {
252 type Buffer = SqliteBindValue<'a>;
253
254 fn push_bound_value<T, U>(&mut self, bind: &'a U, metadata_lookup: &mut ()) -> QueryResult<()>
255 where
256 Sqlite: crate::sql_types::HasSqlType<T>,
257 U: crate::serialize::ToSql<T, Sqlite> + ?Sized,
258 {
259 let value = SqliteBindValue {
260 inner: SqliteBindValueRef::Null,
261 };
262 let mut to_sql_output = Output::new(value, metadata_lookup);
263 let is_null = bind
264 .to_sql(&mut to_sql_output)
265 .map_err(crate::result::Error::SerializationError)?;
266 let bind = to_sql_output.into_inner();
267 let metadata = Sqlite::metadata(metadata_lookup);
268 self.binds.push((
269 match is_null {
270 IsNull::No => bind.inner,
271 IsNull::Yes => SqliteBindValueRef::Null,
272 },
273 metadata,
274 ));
275 Ok(())
276 }
277
278 fn push_null_value(&mut self, metadata: SqliteType) -> QueryResult<()> {
279 self.binds.push((SqliteBindValueRef::Null, metadata));
280 Ok(())
281 }
282}
283
284#[derive(#[automatically_derived]
impl ::core::fmt::Debug for OwnedSqliteBindValue {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
OwnedSqliteBindValue::String(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "String",
&__self_0),
OwnedSqliteBindValue::Binary(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Binary",
&__self_0),
OwnedSqliteBindValue::I32(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "I32",
&__self_0),
OwnedSqliteBindValue::I64(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "I64",
&__self_0),
OwnedSqliteBindValue::F64(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "F64",
&__self_0),
OwnedSqliteBindValue::Null =>
::core::fmt::Formatter::write_str(f, "Null"),
}
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for OwnedSqliteBindValue {
#[inline]
fn clone(&self) -> OwnedSqliteBindValue {
match self {
OwnedSqliteBindValue::String(__self_0) =>
OwnedSqliteBindValue::String(::core::clone::Clone::clone(__self_0)),
OwnedSqliteBindValue::Binary(__self_0) =>
OwnedSqliteBindValue::Binary(::core::clone::Clone::clone(__self_0)),
OwnedSqliteBindValue::I32(__self_0) =>
OwnedSqliteBindValue::I32(::core::clone::Clone::clone(__self_0)),
OwnedSqliteBindValue::I64(__self_0) =>
OwnedSqliteBindValue::I64(::core::clone::Clone::clone(__self_0)),
OwnedSqliteBindValue::F64(__self_0) =>
OwnedSqliteBindValue::F64(::core::clone::Clone::clone(__self_0)),
OwnedSqliteBindValue::Null => OwnedSqliteBindValue::Null,
}
}
}Clone)]
288#[doc = " An owned value bound to a SQLite prepared statement."]
#[doc = ""]
#[doc =
" The readable counterpart to the values a [`SqliteBindCollector`] holds."]
pub enum OwnedSqliteBindValue {
String(Box<str>),
Binary(Box<[u8]>),
I32(i32),
I64(i64),
F64(f64),
Null,
}#[diesel_derives::__diesel_public_if(
289 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
290)]
291enum OwnedSqliteBindValue {
292 String(Box<str>),
294 Binary(Box<[u8]>),
296 I32(i32),
298 I64(i64),
300 F64(f64),
302 Null,
304}
305
306impl<'a> core::convert::From<&SqliteBindValueRef<'a>> for OwnedSqliteBindValue {
307 fn from(value: &SqliteBindValueRef<'a>) -> Self {
308 match value {
309 SqliteBindValueRef::String(s) => Self::String(s.clone()),
310 SqliteBindValueRef::BorrowedString(s) => {
311 Self::String(String::from(*s).into_boxed_str())
312 }
313 SqliteBindValueRef::Binary(b) => Self::Binary(b.clone()),
314 SqliteBindValueRef::BorrowedBinary(s) => Self::Binary(Vec::from(*s).into_boxed_slice()),
315 SqliteBindValueRef::I32(val) => Self::I32(*val),
316 SqliteBindValueRef::I64(val) => Self::I64(*val),
317 SqliteBindValueRef::F64(val) => Self::F64(*val),
318 SqliteBindValueRef::Null => Self::Null,
319 }
320 }
321}
322
323impl core::convert::From<&OwnedSqliteBindValue> for SqliteBindValueRef<'_> {
324 fn from(value: &OwnedSqliteBindValue) -> Self {
325 match value {
326 OwnedSqliteBindValue::String(s) => Self::String(s.clone()),
327 OwnedSqliteBindValue::Binary(b) => Self::Binary(b.clone()),
328 OwnedSqliteBindValue::I32(val) => Self::I32(*val),
329 OwnedSqliteBindValue::I64(val) => Self::I64(*val),
330 OwnedSqliteBindValue::F64(val) => Self::F64(*val),
331 OwnedSqliteBindValue::Null => Self::Null,
332 }
333 }
334}
335
336#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SqliteBindCollectorData {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"SqliteBindCollectorData", "binds", &&self.binds)
}
}Debug)]
345#[doc = " SQLite bind collector data that is movable across threads."]
#[doc = ""]
#[doc =
" This is the [`Send`] snapshot produced by [`MoveableBindCollector::moveable`]"]
#[doc =
" on a [`SqliteBindCollector`]. Both borrowed and owned string or blob variants"]
#[doc =
" of [`SqliteBindValueRef`] collapse into their [`OwnedSqliteBindValue`]"]
#[doc =
" counterparts, so a caller crossing a thread boundary carries no borrows from"]
#[doc = " the original query. For a zero-copy view of the live collector see"]
#[doc = " [`SqliteBindCollector::binds`]."]
#[non_exhaustive]
pub struct SqliteBindCollectorData {
#[doc =
" The collected bind values, in the order they appear in the query."]
binds: Vec<(OwnedSqliteBindValue, SqliteType)>,
}#[diesel_derives::__diesel_public_if(
346 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
347)]
348pub struct SqliteBindCollectorData {
349 binds: Vec<(OwnedSqliteBindValue, SqliteType)>,
351}
352
353impl SqliteBindCollectorData {
354 #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
404 pub fn binds(&self) -> impl ExactSizeIterator<Item = (&OwnedSqliteBindValue, SqliteType)> {
405 self.binds.iter().map(|(v, t)| (v, *t))
406 }
407}
408
409impl MoveableBindCollector<Sqlite> for SqliteBindCollector<'_> {
410 type BindData = SqliteBindCollectorData;
411
412 fn moveable(&self) -> Self::BindData {
413 let mut binds = Vec::with_capacity(self.binds.len());
414 for b in self
415 .binds
416 .iter()
417 .map(|(bind, tpe)| (OwnedSqliteBindValue::from(bind), *tpe))
418 {
419 binds.push(b);
420 }
421 SqliteBindCollectorData { binds }
422 }
423
424 fn append_bind_data(&mut self, from: &Self::BindData) {
425 self.binds.reserve_exact(from.binds.len());
426 self.binds.extend(
427 from.binds
428 .iter()
429 .map(|(bind, tpe)| (SqliteBindValueRef::from(bind), *tpe)),
430 );
431 }
432
433 fn push_debug_binds<'a, 'b>(
434 bind_data: &Self::BindData,
435 f: &'a mut Vec<Box<dyn core::fmt::Debug + 'b>>,
436 ) {
437 f.extend(
438 bind_data
439 .binds
440 .iter()
441 .map(|(b, _)| Box::new(b.clone()) as Box<dyn core::fmt::Debug>),
442 );
443 }
444}
445
446#[cfg(test)]
447mod tests {
448 use super::{
449 OwnedSqliteBindValue, SqliteBindCollector, SqliteBindCollectorData, SqliteBindValueRef,
450 };
451 use crate::expression::IntoSql;
452 use crate::query_builder::{MoveableBindCollector, QueryFragment};
453 use crate::sql_types::{BigInt, Binary, Double, Integer, Nullable, Text};
454 use crate::sqlite::{Sqlite, SqliteType};
455
456 fn collect<Q: QueryFragment<Sqlite>>(query: Q) -> SqliteBindCollectorData {
458 let mut collector = SqliteBindCollector::new();
459 query
460 .collect_binds(&mut collector, &mut (), &Sqlite)
461 .unwrap();
462 collector.moveable()
463 }
464
465 #[diesel_test_helper::test]
466 fn collected_binds_are_readable_in_positional_order_with_their_type() {
467 let data = collect(crate::select((
468 1_i32.into_sql::<Integer>(),
469 2_i64.into_sql::<BigInt>(),
470 3.5_f64.into_sql::<Double>(),
471 "hello".into_sql::<Text>(),
472 vec![1_u8, 2, 3].into_sql::<Binary>(),
473 None::<i32>.into_sql::<Nullable<Integer>>(),
474 )));
475
476 let types: Vec<_> = data.binds.iter().map(|(_, t)| *t).collect();
477 assert_eq!(
478 types,
479 [
480 SqliteType::Integer,
481 SqliteType::Long,
482 SqliteType::Double,
483 SqliteType::Text,
484 SqliteType::Binary,
485 SqliteType::Integer,
486 ]
487 );
488
489 assert!(matches!(data.binds[0].0, OwnedSqliteBindValue::I32(1)));
490 assert!(matches!(data.binds[1].0, OwnedSqliteBindValue::I64(2)));
491 assert!(matches!(data.binds[2].0, OwnedSqliteBindValue::F64(f) if f == 3.5));
492 assert!(matches!(&data.binds[3].0, OwnedSqliteBindValue::String(s) if &**s == "hello"));
493 assert!(matches!(&data.binds[4].0, OwnedSqliteBindValue::Binary(b) if **b == [1, 2, 3]));
494 assert!(matches!(data.binds[5].0, OwnedSqliteBindValue::Null));
495 }
496
497 #[diesel_test_helper::test]
499 fn moveable_owns_every_internal_variant() {
500 let collector = SqliteBindCollector {
501 binds: vec![
502 (
503 SqliteBindValueRef::BorrowedString("borrowed"),
504 SqliteType::Text,
505 ),
506 (SqliteBindValueRef::String("owned".into()), SqliteType::Text),
507 (
508 SqliteBindValueRef::BorrowedBinary(&[1, 2]),
509 SqliteType::Binary,
510 ),
511 (
512 SqliteBindValueRef::Binary(vec![3, 4].into()),
513 SqliteType::Binary,
514 ),
515 (SqliteBindValueRef::I32(7), SqliteType::Integer),
516 (SqliteBindValueRef::I64(8), SqliteType::Long),
517 (SqliteBindValueRef::F64(9.0), SqliteType::Double),
518 (SqliteBindValueRef::Null, SqliteType::Text),
519 ],
520 };
521
522 let data = collector.moveable();
523 assert!(matches!(&data.binds[0].0, OwnedSqliteBindValue::String(s) if &**s == "borrowed"));
524 assert!(matches!(&data.binds[1].0, OwnedSqliteBindValue::String(s) if &**s == "owned"));
525 assert!(matches!(&data.binds[2].0, OwnedSqliteBindValue::Binary(b) if **b == [1, 2]));
526 assert!(matches!(&data.binds[3].0, OwnedSqliteBindValue::Binary(b) if **b == [3, 4]));
527 assert!(matches!(data.binds[4].0, OwnedSqliteBindValue::I32(7)));
528 assert!(matches!(data.binds[5].0, OwnedSqliteBindValue::I64(8)));
529 assert!(matches!(data.binds[6].0, OwnedSqliteBindValue::F64(f) if f == 9.0));
530 assert!(matches!(data.binds[7].0, OwnedSqliteBindValue::Null));
531 }
532
533 #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
536 #[diesel_test_helper::test]
537 fn binds_iterator_yields_live_ref_without_cloning() {
538 let collector = SqliteBindCollector {
539 binds: vec![
540 (
541 SqliteBindValueRef::BorrowedString("borrowed"),
542 SqliteType::Text,
543 ),
544 (
545 SqliteBindValueRef::BorrowedBinary(&[9, 9]),
546 SqliteType::Binary,
547 ),
548 (SqliteBindValueRef::I32(1), SqliteType::Integer),
549 (SqliteBindValueRef::Null, SqliteType::Text),
550 ],
551 };
552
553 let seen: Vec<_> = collector.binds().collect();
554 assert_eq!(seen.len(), 4);
555 assert_eq!(seen[0].1, SqliteType::Text);
556 assert_eq!(seen[1].1, SqliteType::Binary);
557 assert!(matches!(
558 seen[0].0,
559 SqliteBindValueRef::BorrowedString("borrowed")
560 ));
561 assert!(matches!(seen[1].0, SqliteBindValueRef::BorrowedBinary(b) if *b == [9, 9]));
562 assert!(matches!(seen[2].0, SqliteBindValueRef::I32(1)));
563 assert!(matches!(seen[3].0, SqliteBindValueRef::Null));
564 }
565
566 #[diesel_test_helper::test]
568 fn append_bind_data_round_trips_the_owned_snapshot() {
569 let data = collect(crate::select((
570 42_i32.into_sql::<Integer>(),
571 "text".into_sql::<Text>(),
572 None::<i32>.into_sql::<Nullable<Integer>>(),
573 )));
574
575 let mut collector = SqliteBindCollector::new();
576 collector.append_bind_data(&data);
577 let round_tripped = collector.moveable();
578
579 assert!(matches!(
580 round_tripped.binds[0].0,
581 OwnedSqliteBindValue::I32(42)
582 ));
583 assert!(
584 matches!(&round_tripped.binds[1].0, OwnedSqliteBindValue::String(s) if &**s == "text")
585 );
586 assert!(matches!(
587 round_tripped.binds[2].0,
588 OwnedSqliteBindValue::Null
589 ));
590 }
591}