Skip to content

Commit 55f5b93

Browse files
authored
Merge pull request diesel-rs#1976 from diesel-rs/sg-raw-value-gats
Restructure `Backend::RawValue` to allow non-references
2 parents d4eb2c1 + ec0ce10 commit 55f5b93

13 files changed

Lines changed: 101 additions & 42 deletions

File tree

CHANGELOG.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,28 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
66

77
## Unreleased
88

9+
### Changed
10+
11+
* The way [the `Backend` trait][backend-2-0-0] handles its `RawValue` type has
12+
been changed to allow non-references. Users of this type (e.g. code written
13+
`&DB::RawValue` or `&<DB as Backend>::RawValue>`) should use
14+
[`backend::RawValue<DB>`][raw-value-2-0-0] instead. Implementors of `Backend`
15+
should check the relevant section of [the migration guide][2-0-migration].
16+
17+
[backend-2-0-0]: http://docs.diesel.rs/diesel/backend/trait.Backend.html
18+
[raw-value-2-0-0]: http://docs.diesel.rs/diesel/backend/type.RawValue.html
19+
20+
21+
22+
23+
[2-0-migration]: FIXME write a migration guide
24+
925
## [1.4.1] - 2019-01-24
1026

1127
### Fixed
1228

13-
* This release fixes a minor memory safety issue in SQLite. This bug would only occur in an error handling branch that should never occur in practice.
29+
* This release fixes a minor memory safety issue in SQLite. This bug would only
30+
occur in an error handling branch that should never occur in practice.
1431

1532
## [1.4.0] - 2019-01-20
1633

diesel/src/backend.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ where
3232
Self: HasSqlType<sql_types::Date>,
3333
Self: HasSqlType<sql_types::Time>,
3434
Self: HasSqlType<sql_types::Timestamp>,
35+
Self: for<'a> HasRawValue<'a>,
3536
{
3637
/// The concrete `QueryBuilder` implementation for this backend.
3738
type QueryBuilder: QueryBuilder<Self>;
@@ -41,17 +42,28 @@ where
4142
///
4243
/// [`RawBytesBindCollector`]: ../query_builder/bind_collector/struct.RawBytesBindCollector.html
4344
type BindCollector: BindCollector<Self>;
44-
/// The raw representation of a database value given to `FromSql`.
45-
///
46-
/// Since most backends transmit data as opaque blobs of bytes, this type
47-
/// is usually `[u8]`.
48-
type RawValue: ?Sized;
4945
/// What byte order is used to transmit integers?
5046
///
5147
/// This type is only used if `RawValue` is `[u8]`.
5248
type ByteOrder: ByteOrder;
5349
}
5450

51+
/// The raw representation of a database value given to `FromSql`.
52+
///
53+
/// This trait is separate from `Backend` to imitate `type RawValue<'a>`. It
54+
/// should only be referenced directly by implementors. Users of this type
55+
/// should instead use the [`RawValue`](type.RawValue.html) helper type instead.
56+
pub trait HasRawValue<'a> {
57+
/// The actual type given to `FromSql`, with lifetimes applied. This type
58+
/// should not be used directly. Use the [`RawValue`](type.RawValue.html)
59+
/// helper type instead.
60+
type RawValue;
61+
}
62+
63+
/// A helper type to get the raw representation of a database type given to
64+
/// `FromSql`. Equivalent to `<DB as Backend>::RawValue<'a>`.
65+
pub type RawValue<'a, DB> = <DB as HasRawValue<'a>>::RawValue;
66+
5567
/// Does this backend support `RETURNING` clauses?
5668
pub trait SupportsReturningClause {}
5769
/// Does this backend support the bare `DEFAULT` keyword?

diesel/src/deserialize.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::error::Error;
44
use std::result;
55

6-
use backend::Backend;
6+
use backend::{self, Backend};
77
use row::{NamedRow, Row};
88

99
/// A specialized result type representing the result of deserializing
@@ -71,7 +71,7 @@ pub type Result<T> = result::Result<T, Box<Error + Send + Sync>>;
7171
/// # include!("doctest_setup.rs");
7272
/// #
7373
/// # use schema::users;
74-
/// # use diesel::backend::Backend;
74+
/// # use diesel::backend::{self, Backend};
7575
/// # use diesel::deserialize::Queryable;
7676
/// #
7777
/// struct LowercaseString(String);
@@ -241,7 +241,7 @@ where
241241
/// # include!("doctest_setup.rs");
242242
/// # use diesel::sql_query;
243243
/// # use schema::users;
244-
/// # use diesel::backend::Backend;
244+
/// # use diesel::backend::{self, Backend};
245245
/// # use diesel::deserialize::{self, FromSql};
246246
/// #
247247
/// struct LowercaseString(String);
@@ -257,7 +257,7 @@ where
257257
/// DB: Backend,
258258
/// String: FromSql<ST, DB>,
259259
/// {
260-
/// fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> {
260+
/// fn from_sql(bytes: Option<backend::RawValue<DB>>) -> deserialize::Result<Self> {
261261
/// String::from_sql(bytes)
262262
/// .map(|s| LowercaseString(s.to_lowercase()))
263263
/// }
@@ -321,7 +321,7 @@ where
321321
/// implementation.
322322
///
323323
/// ```rust
324-
/// # use diesel::backend::Backend;
324+
/// # use diesel::backend::{self, Backend};
325325
/// # use diesel::sql_types::*;
326326
/// # use diesel::deserialize::{self, FromSql};
327327
/// #
@@ -337,7 +337,7 @@ where
337337
/// DB: Backend,
338338
/// i32: FromSql<Integer, DB>,
339339
/// {
340-
/// fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> {
340+
/// fn from_sql(bytes: Option<backend::RawValue<DB>>) -> deserialize::Result<Self> {
341341
/// match i32::from_sql(bytes)? {
342342
/// 1 => Ok(MyEnum::A),
343343
/// 2 => Ok(MyEnum::B),
@@ -348,7 +348,7 @@ where
348348
/// ```
349349
pub trait FromSql<A, DB: Backend>: Sized {
350350
/// See the trait documentation.
351-
fn from_sql(bytes: Option<&DB::RawValue>) -> Result<Self>;
351+
fn from_sql(bytes: Option<backend::RawValue<DB>>) -> Result<Self>;
352352
}
353353

354354
/// Deserialize one or more fields.

diesel/src/mysql/backend.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,13 @@ pub enum MysqlType {
4949
impl Backend for Mysql {
5050
type QueryBuilder = MysqlQueryBuilder;
5151
type BindCollector = MysqlBindCollector;
52-
type RawValue = [u8];
5352
type ByteOrder = NativeEndian;
5453
}
5554

55+
impl<'a> HasRawValue<'a> for Mysql {
56+
type RawValue = &'a [u8];
57+
}
58+
5659
impl TypeMetadata for Mysql {
5760
type TypeMetadata = MysqlType;
5861
type MetadataLookup = ();

diesel/src/mysql/types/numeric.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub mod bigdecimal {
55
use self::bigdecimal::BigDecimal;
66
use std::io::prelude::*;
77

8-
use backend::Backend;
8+
use backend;
99
use deserialize::{self, FromSql};
1010
use mysql::Mysql;
1111
use serialize::{self, IsNull, Output, ToSql};
@@ -20,7 +20,7 @@ pub mod bigdecimal {
2020
}
2121

2222
impl FromSql<Numeric, Mysql> for BigDecimal {
23-
fn from_sql(bytes: Option<&<Mysql as Backend>::RawValue>) -> deserialize::Result<Self> {
23+
fn from_sql(bytes: Option<backend::RawValue<Mysql>>) -> deserialize::Result<Self> {
2424
let bytes_ptr = <*const [u8] as FromSql<Binary, Mysql>>::from_sql(bytes)?;
2525
let bytes = unsafe { &*bytes_ptr };
2626
BigDecimal::parse_bytes(bytes, 10)

diesel/src/pg/backend.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,13 @@ impl Queryable<(Oid, Oid), Pg> for PgTypeMetadata {
3939
impl Backend for Pg {
4040
type QueryBuilder = PgQueryBuilder;
4141
type BindCollector = RawBytesBindCollector<Pg>;
42-
type RawValue = [u8];
4342
type ByteOrder = NetworkEndian;
4443
}
4544

45+
impl<'a> HasRawValue<'a> for Pg {
46+
type RawValue = &'a [u8];
47+
}
48+
4649
impl TypeMetadata for Pg {
4750
type TypeMetadata = PgTypeMetadata;
4851
type MetadataLookup = PgMetadataLookup;

diesel/src/row.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Contains the `Row` trait
22
3-
use backend::Backend;
3+
use backend::{self, Backend};
44
use deserialize::{self, FromSql};
55

66
/// Represents a single database row.
@@ -11,7 +11,7 @@ use deserialize::{self, FromSql};
1111
/// [`FromSqlRow`]: ../deserialize/trait.FromSqlRow.html
1212
pub trait Row<DB: Backend> {
1313
/// Returns the value of the next column in the row.
14-
fn take(&mut self) -> Option<&DB::RawValue>;
14+
fn take(&mut self) -> Option<backend::RawValue<DB>>;
1515

1616
/// Returns whether the next `count` columns are all `NULL`.
1717
///
@@ -62,5 +62,5 @@ pub trait NamedRow<DB: Backend> {
6262
#[doc(hidden)]
6363
fn index_of(&self, column_name: &str) -> Option<usize>;
6464
#[doc(hidden)]
65-
fn get_raw_value(&self, index: usize) -> Option<&DB::RawValue>;
65+
fn get_raw_value(&self, index: usize) -> Option<backend::RawValue<DB>>;
6666
}

diesel/src/sqlite/backend.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,13 @@ pub enum SqliteType {
4141
impl Backend for Sqlite {
4242
type QueryBuilder = SqliteQueryBuilder;
4343
type BindCollector = RawBytesBindCollector<Sqlite>;
44-
type RawValue = SqliteValue;
4544
type ByteOrder = NativeEndian;
4645
}
4746

47+
impl<'a> HasRawValue<'a> for Sqlite {
48+
type RawValue = &'a SqliteValue;
49+
}
50+
4851
impl TypeMetadata for Sqlite {
4952
type TypeMetadata = SqliteType;
5053
type MetadataLookup = ();

diesel/src/sqlite/types/date_and_time/chrono.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ extern crate chrono;
33
use self::chrono::{NaiveDate, NaiveDateTime, NaiveTime};
44
use std::io::Write;
55

6-
use backend::Backend;
6+
use backend;
77
use deserialize::{self, FromSql};
88
use serialize::{self, Output, ToSql};
99
use sql_types::{Date, Text, Time, Timestamp};
@@ -12,7 +12,7 @@ use sqlite::Sqlite;
1212
const SQLITE_DATE_FORMAT: &str = "%F";
1313

1414
impl FromSql<Date, Sqlite> for NaiveDate {
15-
fn from_sql(value: Option<&<Sqlite as Backend>::RawValue>) -> deserialize::Result<Self> {
15+
fn from_sql(value: Option<backend::RawValue<Sqlite>>) -> deserialize::Result<Self> {
1616
let text_ptr = <*const str as FromSql<Date, Sqlite>>::from_sql(value)?;
1717
let text = unsafe { &*text_ptr };
1818
Self::parse_from_str(text, SQLITE_DATE_FORMAT).map_err(Into::into)
@@ -27,7 +27,7 @@ impl ToSql<Date, Sqlite> for NaiveDate {
2727
}
2828

2929
impl FromSql<Time, Sqlite> for NaiveTime {
30-
fn from_sql(value: Option<&<Sqlite as Backend>::RawValue>) -> deserialize::Result<Self> {
30+
fn from_sql(value: Option<backend::RawValue<Sqlite>>) -> deserialize::Result<Self> {
3131
let text_ptr = <*const str as FromSql<Date, Sqlite>>::from_sql(value)?;
3232
let text = unsafe { &*text_ptr };
3333
let valid_time_formats = &[
@@ -54,7 +54,7 @@ impl ToSql<Time, Sqlite> for NaiveTime {
5454
}
5555

5656
impl FromSql<Timestamp, Sqlite> for NaiveDateTime {
57-
fn from_sql(value: Option<&<Sqlite as Backend>::RawValue>) -> deserialize::Result<Self> {
57+
fn from_sql(value: Option<backend::RawValue<Sqlite>>) -> deserialize::Result<Self> {
5858
let text_ptr = <*const str as FromSql<Date, Sqlite>>::from_sql(value)?;
5959
let text = unsafe { &*text_ptr };
6060

diesel/src/type_impls/floats.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ use byteorder::{ReadBytesExt, WriteBytesExt};
22
use std::error::Error;
33
use std::io::prelude::*;
44

5-
use backend::Backend;
5+
use backend::{Backend, HasRawValue};
66
use deserialize::{self, FromSql};
77
use serialize::{self, IsNull, Output, ToSql};
88
use sql_types;
99

10-
impl<DB: Backend<RawValue = [u8]>> FromSql<sql_types::Float, DB> for f32 {
10+
impl<DB> FromSql<sql_types::Float, DB> for f32
11+
where
12+
DB: Backend + for<'a> HasRawValue<'a, RawValue = &'a [u8]>,
13+
{
1114
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
1215
let mut bytes = not_none!(bytes);
1316
debug_assert!(
@@ -29,7 +32,10 @@ impl<DB: Backend> ToSql<sql_types::Float, DB> for f32 {
2932
}
3033
}
3134

32-
impl<DB: Backend<RawValue = [u8]>> FromSql<sql_types::Double, DB> for f64 {
35+
impl<DB> FromSql<sql_types::Double, DB> for f64
36+
where
37+
DB: Backend + for<'a> HasRawValue<'a, RawValue = &'a [u8]>,
38+
{
3339
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
3440
let mut bytes = not_none!(bytes);
3541
debug_assert!(

0 commit comments

Comments
 (0)