Skip to content

Commit dc2eacd

Browse files
authored
Merge pull request diesel-rs#2931 from weiznich/cleanup/backend
Rewrite bind serialization layer
2 parents 6d68142 + 47eac47 commit dc2eacd

209 files changed

Lines changed: 3543 additions & 2510 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
188188

189189
* The MySQL connection is using the CLIENT_FOUND_ROWS from now on. This means that updating rows without changing any values will return the number of matched rows (like most other SQL servers do), as opposed to the number of changed rows.
190190

191+
* The definition of `ToSql::to_sql` and `QueryFragment::walk_ast` has changed to allow serializing values without
192+
copying the value itself. This is useful for database backends like sqlite where you can directly share a buffer
193+
with the database. Beside of the changed signature, existing impls of this trait should remain unchanged in almost
194+
all cases.
195+
191196
### Fixed
192197

193198
* Many types were incorrectly considered non-aggregate when they should not

diesel/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ categories = ["database"]
1313
edition = "2018"
1414

1515
[dependencies]
16-
byteorder = "1.0"
16+
byteorder = { version = "1.0", optional = true }
1717
chrono = { version = "0.4.19", optional = true, default-features = false, features = ["clock", "std"] }
1818
libc = { version = "0.2.0", optional = true }
1919
libsqlite3-sys = { version = ">=0.8.0, <0.24.0", optional = true, features = ["bundled_bindings"] }
@@ -44,7 +44,7 @@ ipnetwork = ">=0.12.2, <0.19.0"
4444
quickcheck = "1.0.3"
4545

4646
[features]
47-
default = ["32-column-tables", "with-deprecated"]
47+
default = ["with-deprecated", "32-column-tables"]
4848
extras = ["chrono", "serde_json", "uuid", "network-address", "numeric", "r2d2"]
4949
unstable = ["diesel_derives/nightly"]
5050
large-tables = ["32-column-tables"]
@@ -59,8 +59,8 @@ without-deprecated = []
5959
with-deprecated = []
6060
network-address = ["ipnetwork", "libc"]
6161
numeric = ["num-bigint", "bigdecimal", "num-traits", "num-integer"]
62-
postgres_backend = ["diesel_derives/postgres", "bitflags"]
63-
mysql_backend = ["diesel_derives/mysql"]
62+
postgres_backend = ["diesel_derives/postgres", "bitflags", "byteorder"]
63+
mysql_backend = ["diesel_derives/mysql", "byteorder"]
6464

6565
[package.metadata.docs.rs]
6666
features = ["postgres", "mysql", "sqlite", "extras"]

diesel/src/backend.rs

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
//! Types which represent various database backends
2-
3-
use byteorder::ByteOrder;
4-
5-
use crate::query_builder::bind_collector::BindCollector;
62
use crate::query_builder::QueryBuilder;
7-
use crate::sql_types::{self, HasSqlType};
3+
use crate::sql_types::{self, HasSqlType, TypeMetadata};
84

95
/// A database backend
106
///
@@ -33,19 +29,24 @@ where
3329
Self: HasSqlType<sql_types::Time>,
3430
Self: HasSqlType<sql_types::Timestamp>,
3531
Self: for<'a> HasRawValue<'a>,
32+
Self: for<'a> HasBindCollector<'a>,
3633
{
3734
/// The concrete `QueryBuilder` implementation for this backend.
3835
type QueryBuilder: QueryBuilder<Self>;
36+
}
37+
38+
/// The bind collector type used to collect query binds for this backend
39+
///
40+
/// This trait is separate from `Backend` to imitate `type BindCollector<'a>`. It
41+
/// should only be referenced directly by implementors. Users of this type
42+
/// should instead use the [`BindCollector`] helper type instead.
43+
pub trait HasBindCollector<'a>: TypeMetadata + Sized {
3944
/// The concrete `BindCollector` implementation for this backend.
4045
///
4146
/// Most backends should use [`RawBytesBindCollector`].
4247
///
4348
/// [`RawBytesBindCollector`]: crate::query_builder::bind_collector::RawBytesBindCollector
44-
type BindCollector: BindCollector<Self>;
45-
/// What byte order is used to transmit integers?
46-
///
47-
/// This type is only used if `RawValue` is `[u8]`.
48-
type ByteOrder: ByteOrder;
49+
type BindCollector: crate::query_builder::bind_collector::BindCollector<'a, Self> + 'a;
4950
}
5051

5152
/// The raw representation of a database value given to `FromSql`.
@@ -60,19 +61,14 @@ pub trait HasRawValue<'a> {
6061
type RawValue;
6162
}
6263

63-
/// A trait indicating that the provided raw value uses a binary representation internally
64-
// That's a false positive, `HasRawValue<'a>` is essentially
65-
// a reference wrapper
66-
#[allow(clippy::wrong_self_convention)]
67-
pub trait BinaryRawValue<'a>: HasRawValue<'a> {
68-
/// Get the underlying binary representation of the raw value
69-
fn as_bytes(value: Self::RawValue) -> &'a [u8];
70-
}
71-
7264
/// A helper type to get the raw representation of a database type given to
7365
/// `FromSql`. Equivalent to `<DB as Backend>::RawValue<'a>`.
7466
pub type RawValue<'a, DB> = <DB as HasRawValue<'a>>::RawValue;
7567

68+
/// A helper type to get the bind collector for a database backend.
69+
/// Equivalent to `<DB as HasBindCollector<'a>>::BindCollector<'a>`j
70+
pub type BindCollector<'a, DB> = <DB as HasBindCollector<'a>>::BindCollector;
71+
7672
/// This trait provides various options to configure the
7773
/// generated SQL for a specific backend.
7874
///

diesel/src/connection/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,20 @@ pub trait SimpleConnection {
2929
/// implementation. This trait is only useful in combination with [`Connection`].
3030
///
3131
/// Implementation wise this is a workaround for GAT's
32-
pub trait ConnectionGatWorkaround<'a, DB: Backend> {
32+
pub trait ConnectionGatWorkaround<'conn, 'query, DB: Backend> {
3333
/// The cursor type returned by [`Connection::load`]
3434
///
3535
/// Users should handle this as opaque type that implements [`Iterator`]
3636
type Cursor: Iterator<Item = QueryResult<Self::Row>>;
3737
/// The row type used as [`Iterator::Item`] for the iterator implementation
3838
/// of [`ConnectionGatWorkaround::Cursor`]
39-
type Row: crate::row::Row<'a, DB>;
39+
type Row: crate::row::Row<'conn, DB>;
4040
}
4141

4242
/// A connection to a database
4343
pub trait Connection: SimpleConnection + Sized + Send
4444
where
45-
Self: for<'a> ConnectionGatWorkaround<'a, <Self as Connection>::Backend>,
45+
Self: for<'a, 'b> ConnectionGatWorkaround<'a, 'b, <Self as Connection>::Backend>,
4646
{
4747
/// The backend this type connects to
4848
type Backend: Backend;
@@ -192,13 +192,13 @@ where
192192
fn execute(&mut self, query: &str) -> QueryResult<usize>;
193193

194194
#[doc(hidden)]
195-
fn load<T>(
196-
&mut self,
195+
fn load<'conn, 'query, T>(
196+
&'conn mut self,
197197
source: T,
198-
) -> QueryResult<<Self as ConnectionGatWorkaround<Self::Backend>>::Cursor>
198+
) -> QueryResult<<Self as ConnectionGatWorkaround<'conn, 'query, Self::Backend>>::Cursor>
199199
where
200200
T: AsQuery,
201-
T::Query: QueryFragment<Self::Backend> + QueryId,
201+
T::Query: QueryFragment<Self::Backend> + QueryId + 'query,
202202
Self::Backend: QueryMetadata<T::SqlType>;
203203

204204
#[doc(hidden)]

diesel/src/connection/statement_cache.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ where
136136
source: &T,
137137
bind_types: &[DB::TypeMetadata],
138138
prepare_fn: F,
139-
) -> QueryResult<MaybeCached<Statement>>
139+
) -> QueryResult<MaybeCached<'_, Statement>>
140140
where
141141
T: QueryFragment<DB> + QueryId,
142142
F: FnOnce(&str, PrepareForCache) -> QueryResult<Statement>,
@@ -226,7 +226,7 @@ where
226226
}
227227
}
228228

229-
pub fn sql<T: QueryFragment<DB>>(&self, source: &T) -> QueryResult<Cow<str>> {
229+
pub fn sql<T: QueryFragment<DB>>(&self, source: &T) -> QueryResult<Cow<'_, str>> {
230230
match *self {
231231
StatementCacheKey::Type(_) => Self::construct_sql(source).map(Cow::Owned),
232232
StatementCacheKey::Sql { ref sql, .. } => Ok(Cow::Borrowed(sql)),

diesel/src/deserialize.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ pub use diesel_derives::QueryableByName;
411411
/// ```
412412
pub trait FromSql<A, DB: Backend>: Sized {
413413
/// See the trait documentation.
414-
fn from_sql(bytes: backend::RawValue<DB>) -> Result<Self>;
414+
fn from_sql(bytes: backend::RawValue<'_, DB>) -> Result<Self>;
415415

416416
/// A specialized variant of `from_sql` for handling null values.
417417
///
@@ -421,7 +421,7 @@ pub trait FromSql<A, DB: Backend>: Sized {
421421
/// If your custom type supports null values you need to provide a
422422
/// custom implementation.
423423
#[inline(always)]
424-
fn from_nullable_sql(bytes: Option<backend::RawValue<DB>>) -> Result<Self> {
424+
fn from_nullable_sql(bytes: Option<backend::RawValue<'_, DB>>) -> Result<Self> {
425425
match bytes {
426426
Some(bytes) => Self::from_sql(bytes),
427427
None => Err(Box::new(crate::result::UnexpectedNullError)),

diesel/src/expression/array_comparison.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use crate::backend::sql_dialect;
22
use crate::backend::Backend;
33
use crate::backend::SqlDialect;
4-
use crate::expression::bound::Bound;
54
use crate::expression::subselect::Subselect;
65
use crate::expression::*;
76
use crate::query_builder::*;
87
use crate::query_builder::{BoxedSelectStatement, SelectStatement};
98
use crate::result::QueryResult;
9+
use crate::serialize::ToSql;
1010
use crate::sql_types::Bool;
1111
use std::marker::PhantomData;
1212

@@ -55,7 +55,7 @@ where
5555
DB: Backend,
5656
Self: QueryFragment<DB, DB::ArrayComparision>,
5757
{
58-
fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
58+
fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
5959
<Self as QueryFragment<DB, DB::ArrayComparision>>::walk_ast(self, pass)
6060
}
6161
}
@@ -68,7 +68,7 @@ where
6868
T: QueryFragment<DB>,
6969
U: QueryFragment<DB> + MaybeEmpty,
7070
{
71-
fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
71+
fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
7272
if self.values.is_empty() {
7373
out.push_sql("1=0");
7474
} else {
@@ -86,7 +86,7 @@ where
8686
DB: Backend,
8787
Self: QueryFragment<DB, DB::ArrayComparision>,
8888
{
89-
fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
89+
fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
9090
<Self as QueryFragment<DB, DB::ArrayComparision>>::walk_ast(self, pass)
9191
}
9292
}
@@ -99,7 +99,7 @@ where
9999
T: QueryFragment<DB>,
100100
U: QueryFragment<DB> + MaybeEmpty,
101101
{
102-
fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
102+
fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
103103
if self.values.is_empty() {
104104
out.push_sql("1=1");
105105
} else {
@@ -215,7 +215,7 @@ where
215215
Self: QueryFragment<DB, DB::ArrayComparision>,
216216
DB: Backend,
217217
{
218-
fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
218+
fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
219219
<Self as QueryFragment<DB, DB::ArrayComparision>>::walk_ast(self, pass)
220220
}
221221
}
@@ -224,11 +224,12 @@ impl<ST, I, DB> QueryFragment<DB, sql_dialect::array_comparision::AnsiSqlArrayCo
224224
for Many<ST, I>
225225
where
226226
DB: Backend
227+
+ HasSqlType<ST>
227228
+ SqlDialect<ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison>,
228229
ST: SingleValue,
229-
for<'a> Bound<ST, &'a I>: QueryFragment<DB>,
230+
I: ToSql<ST, DB>,
230231
{
231-
fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
232+
fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
232233
out.unsafe_to_cache_prepared();
233234
let mut first = true;
234235
for value in &self.0 {
@@ -237,7 +238,7 @@ where
237238
} else {
238239
out.push_sql(", ");
239240
}
240-
Bound::new(value).walk_ast(out.reborrow())?;
241+
out.push_bind_param(value)?;
241242
}
242243
Ok(())
243244
}

diesel/src/expression/assume_not_null.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use crate::backend::Backend;
22
use crate::expression::TypedExpressionType;
33
use crate::expression::*;
4-
use crate::query_builder::select_statement::NoFromClause;
54
use crate::query_builder::*;
65
use crate::query_source::joins::ToInnerJoin;
76
use crate::result::QueryResult;
@@ -30,7 +29,7 @@ where
3029
DB: Backend,
3130
T: QueryFragment<DB>,
3231
{
33-
fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
32+
fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
3433
self.0.walk_ast(pass)
3534
}
3635
}

diesel/src/expression/bound.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub struct Bound<T, U> {
1616
impl<T, U> Bound<T, U> {
1717
pub fn new(item: U) -> Self {
1818
Bound {
19-
item: item,
19+
item,
2020
_marker: PhantomData,
2121
}
2222
}
@@ -34,7 +34,7 @@ where
3434
DB: Backend + HasSqlType<T>,
3535
U: ToSql<T, DB>,
3636
{
37-
fn walk_ast(&self, mut pass: AstPass<DB>) -> QueryResult<()> {
37+
fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
3838
pass.push_bind_param(&self.item)?;
3939
Ok(())
4040
}

diesel/src/expression/coerce.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ where
6060
T: QueryFragment<DB>,
6161
DB: Backend,
6262
{
63-
fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
63+
fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
6464
self.expr.walk_ast(pass)
6565
}
6666
}

0 commit comments

Comments
 (0)