1use crate::QueryResult;
2use crate::query_builder::{BindCollector, BindData, 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]
#[rustc_trivial_field_reads]
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() -> Self {
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]
#[rustc_trivial_field_reads]
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]
#[rustc_trivial_field_reads]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::BorrowedString(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"BorrowedString", &__self_0),
Self::String(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"String", &__self_0),
Self::BorrowedBinary(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"BorrowedBinary", &__self_0),
Self::Binary(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Binary", &__self_0),
Self::I32(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "I32",
&__self_0),
Self::I64(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "I64",
&__self_0),
Self::F64(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "F64",
&__self_0),
Self::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]
#[rustc_trivial_field_reads]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::String(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"String", &__self_0),
Self::Binary(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Binary", &__self_0),
Self::I32(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "I32",
&__self_0),
Self::I64(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "I64",
&__self_0),
Self::F64(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "F64",
&__self_0),
Self::Null => ::core::fmt::Formatter::write_str(f, "Null"),
}
}
}Debug, #[automatically_derived]impl ::core::clone::Clone for OwnedSqliteBindValue {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self {
match self {
Self::String(__self_0) =>
OwnedSqliteBindValue::String(::core::clone::Clone::clone(__self_0)),
Self::Binary(__self_0) =>
OwnedSqliteBindValue::Binary(::core::clone::Clone::clone(__self_0)),
Self::I32(__self_0) =>
OwnedSqliteBindValue::I32(::core::clone::Clone::clone(__self_0)),
Self::I64(__self_0) =>
OwnedSqliteBindValue::I64(::core::clone::Clone::clone(__self_0)),
Self::F64(__self_0) =>
OwnedSqliteBindValue::F64(::core::clone::Clone::clone(__self_0)),
Self::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]
#[rustc_trivial_field_reads]
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
446impl BindData for SqliteBindCollectorData {
447 fn len(&self) -> usize {
448 self.binds.len()
449 }
450}
451
452#[cfg(test)]
453mod tests {
454 use super::{
455 OwnedSqliteBindValue, SqliteBindCollector, SqliteBindCollectorData, SqliteBindValueRef,
456 };
457 use crate::expression::IntoSql;
458 use crate::query_builder::{MoveableBindCollector, QueryFragment};
459 use crate::sql_types::{BigInt, Binary, Double, Integer, Nullable, Text};
460 use crate::sqlite::{Sqlite, SqliteType};
461
462 fn collect<Q: QueryFragment<Sqlite>>(query: Q) -> SqliteBindCollectorData {
464 let mut collector = SqliteBindCollector::new();
465 query
466 .collect_binds(&mut collector, &mut (), &Sqlite)
467 .unwrap();
468 collector.moveable()
469 }
470
471 #[diesel_test_helper::test]
472 fn collected_binds_are_readable_in_positional_order_with_their_type() {
473 let data = collect(crate::select((
474 1_i32.into_sql::<Integer>(),
475 2_i64.into_sql::<BigInt>(),
476 3.5_f64.into_sql::<Double>(),
477 "hello".into_sql::<Text>(),
478 vec![1_u8, 2, 3].into_sql::<Binary>(),
479 None::<i32>.into_sql::<Nullable<Integer>>(),
480 )));
481
482 let types: Vec<_> = data.binds.iter().map(|(_, t)| *t).collect();
483 assert_eq!(
484 types,
485 [
486 SqliteType::Integer,
487 SqliteType::Long,
488 SqliteType::Double,
489 SqliteType::Text,
490 SqliteType::Binary,
491 SqliteType::Integer,
492 ]
493 );
494
495 assert!(matches!(data.binds[0].0, OwnedSqliteBindValue::I32(1)));
496 assert!(matches!(data.binds[1].0, OwnedSqliteBindValue::I64(2)));
497 assert!(matches!(data.binds[2].0, OwnedSqliteBindValue::F64(f) if f == 3.5));
498 assert!(matches!(&data.binds[3].0, OwnedSqliteBindValue::String(s) if &**s == "hello"));
499 assert!(matches!(&data.binds[4].0, OwnedSqliteBindValue::Binary(b) if **b == [1, 2, 3]));
500 assert!(matches!(data.binds[5].0, OwnedSqliteBindValue::Null));
501 }
502
503 #[diesel_test_helper::test]
505 fn moveable_owns_every_internal_variant() {
506 let collector = SqliteBindCollector {
507 binds: vec![
508 (
509 SqliteBindValueRef::BorrowedString("borrowed"),
510 SqliteType::Text,
511 ),
512 (SqliteBindValueRef::String("owned".into()), SqliteType::Text),
513 (
514 SqliteBindValueRef::BorrowedBinary(&[1, 2]),
515 SqliteType::Binary,
516 ),
517 (
518 SqliteBindValueRef::Binary(vec![3, 4].into()),
519 SqliteType::Binary,
520 ),
521 (SqliteBindValueRef::I32(7), SqliteType::Integer),
522 (SqliteBindValueRef::I64(8), SqliteType::Long),
523 (SqliteBindValueRef::F64(9.0), SqliteType::Double),
524 (SqliteBindValueRef::Null, SqliteType::Text),
525 ],
526 };
527
528 let data = collector.moveable();
529 assert!(matches!(&data.binds[0].0, OwnedSqliteBindValue::String(s) if &**s == "borrowed"));
530 assert!(matches!(&data.binds[1].0, OwnedSqliteBindValue::String(s) if &**s == "owned"));
531 assert!(matches!(&data.binds[2].0, OwnedSqliteBindValue::Binary(b) if **b == [1, 2]));
532 assert!(matches!(&data.binds[3].0, OwnedSqliteBindValue::Binary(b) if **b == [3, 4]));
533 assert!(matches!(data.binds[4].0, OwnedSqliteBindValue::I32(7)));
534 assert!(matches!(data.binds[5].0, OwnedSqliteBindValue::I64(8)));
535 assert!(matches!(data.binds[6].0, OwnedSqliteBindValue::F64(f) if f == 9.0));
536 assert!(matches!(data.binds[7].0, OwnedSqliteBindValue::Null));
537 }
538
539 #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
542 #[diesel_test_helper::test]
543 fn binds_iterator_yields_live_ref_without_cloning() {
544 let collector = SqliteBindCollector {
545 binds: vec![
546 (
547 SqliteBindValueRef::BorrowedString("borrowed"),
548 SqliteType::Text,
549 ),
550 (
551 SqliteBindValueRef::BorrowedBinary(&[9, 9]),
552 SqliteType::Binary,
553 ),
554 (SqliteBindValueRef::I32(1), SqliteType::Integer),
555 (SqliteBindValueRef::Null, SqliteType::Text),
556 ],
557 };
558
559 let seen: Vec<_> = collector.binds().collect();
560 assert_eq!(seen.len(), 4);
561 assert_eq!(seen[0].1, SqliteType::Text);
562 assert_eq!(seen[1].1, SqliteType::Binary);
563 assert!(matches!(
564 seen[0].0,
565 SqliteBindValueRef::BorrowedString("borrowed")
566 ));
567 assert!(matches!(seen[1].0, SqliteBindValueRef::BorrowedBinary(b) if *b == [9, 9]));
568 assert!(matches!(seen[2].0, SqliteBindValueRef::I32(1)));
569 assert!(matches!(seen[3].0, SqliteBindValueRef::Null));
570 }
571
572 #[diesel_test_helper::test]
574 fn append_bind_data_round_trips_the_owned_snapshot() {
575 let data = collect(crate::select((
576 42_i32.into_sql::<Integer>(),
577 "text".into_sql::<Text>(),
578 None::<i32>.into_sql::<Nullable<Integer>>(),
579 )));
580
581 let mut collector = SqliteBindCollector::new();
582 collector.append_bind_data(&data);
583 let round_tripped = collector.moveable();
584
585 assert!(matches!(
586 round_tripped.binds[0].0,
587 OwnedSqliteBindValue::I32(42)
588 ));
589 assert!(
590 matches!(&round_tripped.binds[1].0, OwnedSqliteBindValue::String(s) if &**s == "text")
591 );
592 assert!(matches!(
593 round_tripped.binds[2].0,
594 OwnedSqliteBindValue::Null
595 ));
596 }
597}