Skip to content

Commit 385f445

Browse files
committed
Separate raw value representations of postgresql and mysql backend
This commit separates the raw value representation of the mysql and postgresql backend from raw `&[u8]` to specific types that could hold additional information. To avoid code duplication for commonly used types an additional trait (`BinaryRawValue`) is introduced, which is basically equivalent to `AsRef<[u8]>` but has the existing `HasRawValue` trait as super trait. This is required to workaround some higher ranked life time issues in rustc. Additionally some type information are added to the postgresql value type. Those information may allow to do dynamic type conversations in future diesel versions.
1 parent 2b06165 commit 385f445

36 files changed

Lines changed: 362 additions & 179 deletions

diesel/src/backend.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ pub trait HasRawValue<'a> {
6060
type RawValue;
6161
}
6262

63+
/// A trait indicating that the provided raw value uses a binary representation internally
64+
pub trait BinaryRawValue<'a>: HasRawValue<'a> {
65+
/// Get the underlying binary representation of the raw value
66+
fn as_bytes(value: Self::RawValue) -> &'a [u8];
67+
}
68+
6369
/// A helper type to get the raw representation of a database type given to
6470
/// `FromSql`. Equivalent to `<DB as Backend>::RawValue<'a>`.
6571
pub type RawValue<'a, DB> = <DB as HasRawValue<'a>>::RawValue;

diesel/src/mysql/backend.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use byteorder::NativeEndian;
44

55
use super::query_builder::MysqlQueryBuilder;
6+
use super::MysqlValue;
67
use backend::*;
78
use query_builder::bind_collector::RawBytesBindCollector;
89
use sql_types::TypeMetadata;
@@ -69,7 +70,7 @@ impl Backend for Mysql {
6970
}
7071

7172
impl<'a> HasRawValue<'a> for Mysql {
72-
type RawValue = &'a [u8];
73+
type RawValue = MysqlValue<'a>;
7374
}
7475

7576
impl TypeMetadata for Mysql {

diesel/src/mysql/connection/bind.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::mem;
44
use std::os::raw as libc;
55

66
use super::stmt::Statement;
7-
use mysql::{MysqlType, MysqlTypeMetadata};
7+
use mysql::{MysqlType, MysqlTypeMetadata, MysqlValue};
88
use result::QueryResult;
99

1010
pub struct Binds {
@@ -23,7 +23,7 @@ impl Binds {
2323
})
2424
.collect();
2525

26-
Binds { data: data }
26+
Binds { data }
2727
}
2828

2929
pub fn from_output_types(types: Vec<MysqlTypeMetadata>) -> Self {
@@ -38,7 +38,7 @@ impl Binds {
3838
.map(BindData::for_output)
3939
.collect();
4040

41-
Binds { data: data }
41+
Binds { data }
4242
}
4343

4444
pub fn from_result_metadata(fields: &[ffi::MYSQL_FIELD]) -> Self {
@@ -86,8 +86,8 @@ impl Binds {
8686
}
8787
}
8888

89-
pub fn field_data(&self, idx: usize) -> Option<&[u8]> {
90-
self.data[idx].bytes()
89+
pub fn field_data(&self, idx: usize) -> Option<MysqlValue> {
90+
self.data[idx].bytes().map(MysqlValue::new)
9191
}
9292
}
9393

diesel/src/mysql/connection/stmt/iterator.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::HashMap;
22

33
use super::{ffi, libc, Binds, Statement, StatementMetadata};
4-
use mysql::{Mysql, MysqlTypeMetadata};
4+
use mysql::{Mysql, MysqlTypeMetadata, MysqlValue};
55
use result::QueryResult;
66
use row::*;
77

@@ -18,10 +18,7 @@ impl<'a> StatementIterator<'a> {
1818

1919
execute_statement(stmt, &mut output_binds)?;
2020

21-
Ok(StatementIterator {
22-
stmt: stmt,
23-
output_binds: output_binds,
24-
})
21+
Ok(StatementIterator { stmt, output_binds })
2522
}
2623

2724
pub fn map<F, T>(mut self, mut f: F) -> QueryResult<Vec<T>>
@@ -53,7 +50,7 @@ pub struct MysqlRow<'a> {
5350
}
5451

5552
impl<'a> Row<Mysql> for MysqlRow<'a> {
56-
fn take(&mut self) -> Option<&[u8]> {
53+
fn take(&mut self) -> Option<MysqlValue> {
5754
let current_idx = self.col_idx;
5855
self.col_idx += 1;
5956
self.binds.field_data(current_idx)
@@ -119,7 +116,7 @@ impl<'a> NamedRow<Mysql> for NamedMysqlRow<'a> {
119116
self.column_indices.get(column_name).cloned()
120117
}
121118

122-
fn get_raw_value(&self, idx: usize) -> Option<&[u8]> {
119+
fn get_raw_value(&self, idx: usize) -> Option<MysqlValue> {
123120
self.binds.field_data(idx)
124121
}
125122
}

diesel/src/mysql/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
77
mod backend;
88
mod connection;
9+
mod value;
910

1011
mod query_builder;
1112
pub mod types;
1213

1314
pub use self::backend::{Mysql, MysqlType, MysqlTypeMetadata};
1415
pub use self::connection::MysqlConnection;
1516
pub use self::query_builder::MysqlQueryBuilder;
17+
pub use self::value::MysqlValue;

diesel/src/mysql/types/date_and_time.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::os::raw as libc;
77
use std::{mem, ptr, slice};
88

99
use deserialize::{self, FromSql};
10-
use mysql::Mysql;
10+
use mysql::{Mysql, MysqlValue};
1111
use serialize::{self, IsNull, Output, ToSql};
1212
use sql_types::{Date, Datetime, Time, Timestamp};
1313

@@ -25,9 +25,9 @@ macro_rules! mysql_time_impls {
2525
}
2626

2727
impl FromSql<$ty, Mysql> for ffi::MYSQL_TIME {
28-
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
29-
let bytes = not_none!(bytes);
30-
let bytes_ptr = bytes.as_ptr() as *const ffi::MYSQL_TIME;
28+
fn from_sql(value: Option<MysqlValue>) -> deserialize::Result<Self> {
29+
let value = not_none!(value);
30+
let bytes_ptr = value.as_bytes().as_ptr() as *const ffi::MYSQL_TIME;
3131
unsafe {
3232
let mut result = mem::MaybeUninit::uninit();
3333
ptr::copy_nonoverlapping(bytes_ptr, result.as_mut_ptr(), 1);
@@ -55,7 +55,7 @@ impl ToSql<Datetime, Mysql> for NaiveDateTime {
5555
}
5656

5757
impl FromSql<Datetime, Mysql> for NaiveDateTime {
58-
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
58+
fn from_sql(bytes: Option<MysqlValue>) -> deserialize::Result<Self> {
5959
<NaiveDateTime as FromSql<Timestamp, Mysql>>::from_sql(bytes)
6060
}
6161
}
@@ -77,7 +77,7 @@ impl ToSql<Timestamp, Mysql> for NaiveDateTime {
7777
}
7878

7979
impl FromSql<Timestamp, Mysql> for NaiveDateTime {
80-
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
80+
fn from_sql(bytes: Option<MysqlValue>) -> deserialize::Result<Self> {
8181
let mysql_time = <ffi::MYSQL_TIME as FromSql<Timestamp, Mysql>>::from_sql(bytes)?;
8282

8383
NaiveDate::from_ymd_opt(
@@ -110,7 +110,7 @@ impl ToSql<Time, Mysql> for NaiveTime {
110110
}
111111

112112
impl FromSql<Time, Mysql> for NaiveTime {
113-
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
113+
fn from_sql(bytes: Option<MysqlValue>) -> deserialize::Result<Self> {
114114
let mysql_time = <ffi::MYSQL_TIME as FromSql<Time, Mysql>>::from_sql(bytes)?;
115115
NaiveTime::from_hms_opt(
116116
mysql_time.hour as u32,
@@ -134,7 +134,7 @@ impl ToSql<Date, Mysql> for NaiveDate {
134134
}
135135

136136
impl FromSql<Date, Mysql> for NaiveDate {
137-
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
137+
fn from_sql(bytes: Option<MysqlValue>) -> deserialize::Result<Self> {
138138
let mysql_time = <ffi::MYSQL_TIME as FromSql<Date, Mysql>>::from_sql(bytes)?;
139139
NaiveDate::from_ymd_opt(
140140
mysql_time.year as i32,

diesel/src/mysql/types/mod.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use byteorder::WriteBytesExt;
88
use std::io::Write;
99

1010
use deserialize::{self, FromSql};
11-
use mysql::{Mysql, MysqlTypeMetadata};
11+
use mysql::{Mysql, MysqlTypeMetadata, MysqlValue};
1212
use serialize::{self, IsNull, Output, ToSql};
1313
use sql_types::*;
1414

@@ -19,8 +19,9 @@ impl ToSql<TinyInt, Mysql> for i8 {
1919
}
2020

2121
impl FromSql<TinyInt, Mysql> for i8 {
22-
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
23-
let bytes = not_none!(bytes);
22+
fn from_sql(value: Option<MysqlValue>) -> deserialize::Result<Self> {
23+
let value = not_none!(value);
24+
let bytes = value.as_bytes();
2425
Ok(bytes[0] as i8)
2526
}
2627
}
@@ -36,7 +37,7 @@ impl ToSql<Unsigned<TinyInt>, Mysql> for u8 {
3637
}
3738

3839
impl FromSql<Unsigned<TinyInt>, Mysql> for u8 {
39-
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
40+
fn from_sql(bytes: Option<MysqlValue>) -> deserialize::Result<Self> {
4041
let signed: i8 = FromSql::<TinyInt, Mysql>::from_sql(bytes)?;
4142
Ok(signed as u8)
4243
}
@@ -49,7 +50,7 @@ impl ToSql<Unsigned<SmallInt>, Mysql> for u16 {
4950
}
5051

5152
impl FromSql<Unsigned<SmallInt>, Mysql> for u16 {
52-
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
53+
fn from_sql(bytes: Option<MysqlValue>) -> deserialize::Result<Self> {
5354
let signed: i16 = FromSql::<SmallInt, Mysql>::from_sql(bytes)?;
5455
Ok(signed as u16)
5556
}
@@ -62,7 +63,7 @@ impl ToSql<Unsigned<Integer>, Mysql> for u32 {
6263
}
6364

6465
impl FromSql<Unsigned<Integer>, Mysql> for u32 {
65-
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
66+
fn from_sql(bytes: Option<MysqlValue>) -> deserialize::Result<Self> {
6667
let signed: i32 = FromSql::<Integer, Mysql>::from_sql(bytes)?;
6768
Ok(signed as u32)
6869
}
@@ -75,7 +76,7 @@ impl ToSql<Unsigned<BigInt>, Mysql> for u64 {
7576
}
7677

7778
impl FromSql<Unsigned<BigInt>, Mysql> for u64 {
78-
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
79+
fn from_sql(bytes: Option<MysqlValue>) -> deserialize::Result<Self> {
7980
let signed: i64 = FromSql::<BigInt, Mysql>::from_sql(bytes)?;
8081
Ok(signed as u64)
8182
}
@@ -89,8 +90,8 @@ impl ToSql<Bool, Mysql> for bool {
8990
}
9091

9192
impl FromSql<Bool, Mysql> for bool {
92-
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
93-
Ok(not_none!(bytes).iter().any(|x| *x != 0))
93+
fn from_sql(bytes: Option<MysqlValue>) -> deserialize::Result<Self> {
94+
Ok(not_none!(bytes).as_bytes().iter().any(|x| *x != 0))
9495
}
9596
}
9697

diesel/src/mysql/value.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use super::Mysql;
2+
use backend::BinaryRawValue;
3+
4+
/// Raw mysql value as received from the database
5+
#[derive(Copy, Clone, Debug)]
6+
pub struct MysqlValue<'a> {
7+
raw: &'a [u8],
8+
}
9+
10+
impl<'a> MysqlValue<'a> {
11+
pub(crate) fn new(raw: &'a [u8]) -> Self {
12+
Self { raw }
13+
}
14+
15+
/// Get the underlying raw byte representation
16+
pub fn as_bytes(&self) -> &[u8] {
17+
self.raw
18+
}
19+
}
20+
21+
impl<'a> BinaryRawValue<'a> for Mysql {
22+
fn as_bytes(value: Self::RawValue) -> &'a [u8] {
23+
value.raw
24+
}
25+
}

diesel/src/pg/backend.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use byteorder::NetworkEndian;
44

55
use super::query_builder::PgQueryBuilder;
6-
use super::PgMetadataLookup;
6+
use super::{PgMetadataLookup, PgValue};
77
use backend::*;
88
use deserialize::Queryable;
99
use query_builder::bind_collector::RawBytesBindCollector;
@@ -43,7 +43,7 @@ impl Backend for Pg {
4343
}
4444

4545
impl<'a> HasRawValue<'a> for Pg {
46-
type RawValue = &'a [u8];
46+
type RawValue = PgValue<'a>;
4747
}
4848

4949
impl TypeMetadata for Pg {

diesel/src/pg/connection/cursor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ impl<ST, T> Cursor<ST, T> {
2020
pub fn new(db_result: PgResult) -> Self {
2121
Cursor {
2222
current_row: 0,
23-
db_result: db_result,
23+
db_result,
2424
_marker: PhantomData,
2525
}
2626
}
@@ -47,7 +47,7 @@ where
4747
}
4848

4949
pub struct NamedCursor {
50-
db_result: PgResult,
50+
pub(crate) db_result: PgResult,
5151
}
5252

5353
impl NamedCursor {

0 commit comments

Comments
 (0)