1//! Types related to managing bind parameters during query construction.
23use crate::backend::Backend;
4use crate::result::Error::SerializationError;
5use crate::result::QueryResult;
6use crate::serialize::{IsNull, Output, ToSql};
7use crate::sql_types::{HasSqlType, TypeMetadata};
89#[doc(inline)]
10#[doc(inline)]
pub use self::private::ByteWrapper;#[diesel_derives::__diesel_public_if(
11 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
12)]13pub(crate) use self::private::ByteWrapper;
1415/// A type which manages serializing bind parameters during query construction.
16///
17/// The only reason you would ever need to interact with this trait is if you
18/// are adding support for a new backend to Diesel. Plugins which are extending
19/// the query builder will use [`AstPass::push_bind_param`] instead.
20///
21/// [`AstPass::push_bind_param`]: crate::query_builder::AstPass::push_bind_param()
22pub trait BindCollector<'a, DB: TypeMetadata>: Sized {
23/// The internal buffer type used by this bind collector
24type Buffer;
2526/// Serializes the given bind value, and collects the result.
27fn push_bound_value<T, U>(
28&mut self,
29 bind: &'a U,
30 metadata_lookup: &mut DB::MetadataLookup,
31 ) -> QueryResult<()>
32where
33DB: Backend + HasSqlType<T>,
34 U: ToSql<T, DB> + ?Sized + 'a;
3536/// Push a null value with the given type information onto the bind collector
37// For backward compatibility reasons we provide a default implementation
38 // but custom backends that want to support `#[derive(MultiConnection)]`
39 // need to provide a customized implementation of this function
40#[diesel_derives::__diesel_public_if(
41 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
42)]
43fn push_null_value(&mut self, _metadata: DB::TypeMetadata) -> QueryResult<()> {
44Ok(())
45 }
46}
4748/// A movable version of the bind collector which allows it to be extracted, moved and refilled.
49///
50/// This is mostly useful in async context where bind data needs to be moved across threads.
51#[doc =
" A movable version of the bind collector which allows it to be extracted, moved and refilled."]
#[doc = ""]
#[doc =
" This is mostly useful in async context where bind data needs to be moved across threads."]
pub trait MoveableBindCollector<DB: TypeMetadata> {
/// The movable bind data of this bind collector
type BindData: Send + 'static;
/// Builds a movable version of the bind collector
fn moveable(&self)
-> Self::BindData;
/// Refill the bind collector with its bind data
fn append_bind_data(&mut self, from: &Self::BindData);
/// Push bind data as debug representation
fn push_debug_binds<'a,
'b>(bind_data: &Self::BindData,
f: &'a mut Vec<Box<dyn std::fmt::Debug + 'b>>);
}#[diesel_derives::__diesel_public_if(
52 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
53)]54pub trait MoveableBindCollector<DB: TypeMetadata> {
55/// The movable bind data of this bind collector
56type BindData: Send + 'static;
5758/// Builds a movable version of the bind collector
59fn moveable(&self) -> Self::BindData;
6061/// Refill the bind collector with its bind data
62fn append_bind_data(&mut self, from: &Self::BindData);
6364/// Push bind data as debug representation
65fn push_debug_binds<'a, 'b>(
66 bind_data: &Self::BindData,
67 f: &'a mut Vec<Box<dyn std::fmt::Debug + 'b>>,
68 );
69}
7071#[derive(#[automatically_derived]
impl<DB: ::core::fmt::Debug + Backend + TypeMetadata> ::core::fmt::Debug for
RawBytesBindCollector<DB> where DB::TypeMetadata: ::core::fmt::Debug {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"RawBytesBindCollector", "metadata", &self.metadata, "binds",
&&self.binds)
}
}Debug)]
72/// A bind collector used by backends which transmit bind parameters as an
73/// opaque blob of bytes.
74///
75/// For most backends, this is the concrete implementation of `BindCollector`
76/// that should be used.
77#[doc =
" A bind collector used by backends which transmit bind parameters as an"]
#[doc = " opaque blob of bytes."]
#[doc = ""]
#[doc =
" For most backends, this is the concrete implementation of `BindCollector`"]
#[doc = " that should be used."]
#[non_exhaustive]
pub struct RawBytesBindCollector<DB: Backend + TypeMetadata> {
#[doc = " The metadata associated with each bind parameter."]
#[doc = ""]
#[doc = " This vec is guaranteed to be the same length as `binds`."]
pub metadata: Vec<DB::TypeMetadata>,
#[doc = " The serialized bytes for each bind parameter."]
#[doc = ""]
#[doc = " This vec is guaranteed to be the same length as `metadata`."]
pub binds: Vec<Option<Vec<u8>>>,
}#[diesel_derives::__diesel_public_if(
78 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
79 public_fields(metadata, binds)
80)]81pub struct RawBytesBindCollector<DB: Backend + TypeMetadata> {
82/// The metadata associated with each bind parameter.
83 ///
84 /// This vec is guaranteed to be the same length as `binds`.
85pub(crate) metadata: Vec<DB::TypeMetadata>,
86/// The serialized bytes for each bind parameter.
87 ///
88 /// This vec is guaranteed to be the same length as `metadata`.
89pub(crate) binds: Vec<Option<Vec<u8>>>,
90}
9192impl<DB: Backend + TypeMetadata> Defaultfor RawBytesBindCollector<DB> {
93fn default() -> Self {
94Self::new()
95 }
96}
9798#[allow(clippy::new_without_default)]
99impl<DB: Backend + TypeMetadata> RawBytesBindCollector<DB> {
100/// Construct an empty `RawBytesBindCollector`
101pub fn new() -> Self {
102RawBytesBindCollector {
103 metadata: Vec::new(),
104 binds: Vec::new(),
105 }
106 }
107108pub(crate) fn reborrow_buffer<'a: 'b, 'b>(b: &'b mut ByteWrapper<'a>) -> ByteWrapper<'b> {
109ByteWrapper(b.0)
110 }
111}
112113impl<'a, DB> BindCollector<'a, DB> for RawBytesBindCollector<DB>
114where
115 for<'b> DB: Backend<BindCollector<'b> = Self> + TypeMetadata,
116{
117type Buffer = ByteWrapper<'a>;
118119fn push_bound_value<T, U>(
120&mut self,
121 bind: &U,
122 metadata_lookup: &mut DB::MetadataLookup,
123 ) -> QueryResult<()>
124where
125DB: HasSqlType<T>,
126 U: ToSql<T, DB> + ?Sized,
127 {
128let mut bytes = Vec::new();
129let is_null = {
130let mut to_sql_output = Output::new(ByteWrapper(&mut bytes), metadata_lookup);
131bind.to_sql(&mut to_sql_output)
132 .map_err(SerializationError)?
133};
134let metadata = <DB as HasSqlType<T>>::metadata(metadata_lookup);
135match is_null {
136 IsNull::No => self.binds.push(Some(bytes)),
137 IsNull::Yes => self.binds.push(None),
138 }
139self.metadata.push(metadata);
140Ok(())
141 }
142143fn push_null_value(&mut self, metadata: DB::TypeMetadata) -> QueryResult<()> {
144self.metadata.push(metadata);
145self.binds.push(None);
146Ok(())
147 }
148}
149150impl<DB> MoveableBindCollector<DB> for RawBytesBindCollector<DB>
151where
152 for<'a> DB: Backend<BindCollector<'a> = Self> + TypeMetadata + 'static,
153 <DB as TypeMetadata>::TypeMetadata: std::fmt::Debug + Clone + Send,
154{
155type BindData = Self;
156157fn moveable(&self) -> Self::BindData {
158RawBytesBindCollector {
159 binds: self.binds.clone(),
160 metadata: self.metadata.clone(),
161 }
162 }
163164fn append_bind_data(&mut self, from: &Self::BindData) {
165self.binds.extend(from.binds.iter().cloned());
166self.metadata.extend(from.metadata.clone());
167 }
168169fn push_debug_binds<'a, 'b>(
170 bind_data: &Self::BindData,
171 f: &'a mut Vec<Box<dyn std::fmt::Debug + 'b>>,
172 ) {
173f.extend(
174bind_data175 .metadata
176 .iter()
177 .map(|m| Box::new(m.clone()) as Box<dyn std::fmt::Debug>),
178 );
179 }
180}
181182// This is private for now as we may want to add `Into` impls for the wrapper type
183// later on
184mod private {
185/// A type wrapper for raw bytes
186#[derive(#[automatically_derived]
impl<'a> ::core::fmt::Debug for ByteWrapper<'a> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "ByteWrapper",
&&self.0)
}
}Debug)]
187pub struct ByteWrapper<'a>(pub(crate) &'a mut Vec<u8>);
188}