1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//! Types related to managing bind parameters during query construction.
use backend::Backend;
use result::Error::SerializationError;
use result::QueryResult;
use serialize::{IsNull, Output, ToSql};
use sql_types::{HasSqlType, TypeMetadata};
/// A type which manages serializing bind parameters during query construction.
///
/// The only reason you would ever need to interact with this trait is if you
/// are adding support for a new backend to Diesel. Plugins which are extending
/// the query builder will use [`AstPass::push_bind_param`] instead.
///
/// [`AstPass::push_bind_param`]: ../struct.AstPass.html#method.push_bind_param
pub trait BindCollector<DB: Backend> {
/// Serializes the given bind value, and collects the result.
fn push_bound_value<T, U>(
&mut self,
bind: &U,
metadata_lookup: &DB::MetadataLookup,
) -> QueryResult<()>
where
DB: HasSqlType<T>,
U: ToSql<T, DB>;
}
#[derive(Debug)]
/// A bind collector used by backends which transmit bind parameters as an
/// opaque blob of bytes.
///
/// For most backends, this is the concrete implementation of `BindCollector`
/// that should be used.
pub struct RawBytesBindCollector<DB: Backend + TypeMetadata> {
/// The metadata associated with each bind parameter.
///
/// This vec is guaranteed to be the same length as `binds`.
pub metadata: Vec<DB::TypeMetadata>,
/// The serialized bytes for each bind parameter.
///
/// This vec is guaranteed to be the same length as `metadata`.
pub binds: Vec<Option<Vec<u8>>>,
}
#[allow(clippy::new_without_default_derive)]
impl<DB: Backend + TypeMetadata> RawBytesBindCollector<DB> {
/// Construct an empty `RawBytesBindCollector`
pub fn new() -> Self {
RawBytesBindCollector {
metadata: Vec::new(),
binds: Vec::new(),
}
}
}
impl<DB: Backend + TypeMetadata> BindCollector<DB> for RawBytesBindCollector<DB> {
fn push_bound_value<T, U>(
&mut self,
bind: &U,
metadata_lookup: &DB::MetadataLookup,
) -> QueryResult<()>
where
DB: HasSqlType<T>,
U: ToSql<T, DB>,
{
let mut to_sql_output = Output::new(Vec::new(), metadata_lookup);
let is_null = bind
.to_sql(&mut to_sql_output)
.map_err(SerializationError)?;
let bytes = to_sql_output.into_inner();
let metadata = <DB as HasSqlType<T>>::metadata(metadata_lookup);
match is_null {
IsNull::No => self.binds.push(Some(bytes)),
IsNull::Yes => self.binds.push(None),
}
self.metadata.push(metadata);
Ok(())
}
}