Skip to content

Commit

Permalink
Merge pull request #2920 from weiznich/split_postgres/mysql_backend_f…
Browse files Browse the repository at this point in the history
…rom_connection

Move the PgConnection and MysqlConnection behind a distinct feature flag
  • Loading branch information
pksunkara authored Oct 9, 2021
2 parents 46696c0 + eb8c383 commit 9cb852b
Show file tree
Hide file tree
Showing 21 changed files with 247 additions and 99 deletions.
6 changes: 4 additions & 2 deletions diesel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,15 @@ huge-tables = ["64-column-tables"]
32-column-tables = []
64-column-tables = ["32-column-tables"]
128-column-tables = ["64-column-tables"]
postgres = ["pq-sys", "bitflags", "diesel_derives/postgres"]
postgres = ["pq-sys", "postgres_backend"]
sqlite = ["libsqlite3-sys", "diesel_derives/sqlite"]
mysql = ["mysqlclient-sys", "url", "percent-encoding", "diesel_derives/mysql", "bitflags"]
mysql = ["mysqlclient-sys", "url", "percent-encoding", "bitflags", "mysql_backend"]
without-deprecated = []
with-deprecated = []
network-address = ["ipnetwork", "libc"]
numeric = ["num-bigint", "bigdecimal", "num-traits", "num-integer"]
postgres_backend = ["diesel_derives/postgres", "bitflags"]
mysql_backend = ["diesel_derives/mysql"]

[package.metadata.docs.rs]
features = ["postgres", "mysql", "sqlite", "extras"]
Expand Down
5 changes: 4 additions & 1 deletion diesel/src/data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
//! confusing (such as date and time types). This module will re-export
//! all backend specific data structures when compiled against that
//! backend.
#[cfg(feature = "postgres")]
#[cfg(feature = "postgres_backend")]
pub use crate::pg::data_types::*;

#[cfg(feature = "mysql_backend")]
pub use crate::mysql::data_types::*;
2 changes: 1 addition & 1 deletion diesel/src/expression/helper_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ pub type NotLike<Lhs, Rhs> = Grouped<super::operators::NotLike<Lhs, AsExprOf<Rhs
pub use super::functions::helper_types::*;

#[doc(inline)]
#[cfg(feature = "postgres")]
#[cfg(feature = "postgres_backend")]
pub use crate::pg::expression::helper_types::*;

#[doc(inline)]
Expand Down
2 changes: 1 addition & 1 deletion diesel/src/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub mod dsl {
#[doc(inline)]
pub use super::sql_literal::sql;

#[cfg(feature = "postgres")]
#[cfg(feature = "postgres_backend")]
pub use crate::pg::expression::dsl::*;

/// The return type of [`count(expr)`](crate::dsl::count())
Expand Down
10 changes: 3 additions & 7 deletions diesel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,6 @@
clippy::used_underscore_binding
)]

#[cfg(feature = "postgres")]
#[macro_use]
extern crate bitflags;
extern crate byteorder;
extern crate diesel_derives;

#[macro_use]
Expand Down Expand Up @@ -162,9 +158,9 @@ pub mod sql_types;
pub mod migration;
pub mod row;

#[cfg(feature = "mysql")]
#[cfg(feature = "mysql_backend")]
pub mod mysql;
#[cfg(feature = "postgres")]
#[cfg(feature = "postgres_backend")]
pub mod pg;
#[cfg(feature = "sqlite")]
pub mod sqlite;
Expand Down Expand Up @@ -298,7 +294,7 @@ pub mod helper_types {
pub type Distinct<Source> = <Source as DistinctDsl>::Output;

/// Represents the return type of `.distinct_on(expr)`
#[cfg(feature = "postgres")]
#[cfg(feature = "postgres_backend")]
pub type DistinctOn<Source, Expr> = <Source as DistinctOnDsl<Expr>>::Output;

/// Represents the return type of `.single_value()`
Expand Down
4 changes: 2 additions & 2 deletions diesel/src/mysql/connection/bind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::os::raw as libc;
use super::stmt::MysqlFieldMetadata;
use super::stmt::Statement;
use crate::mysql::connection::stmt::StatementMetadata;
use crate::mysql::types::MYSQL_TIME;
use crate::mysql::types::MysqlTime;
use crate::mysql::{MysqlType, MysqlValue};
use crate::result::QueryResult;

Expand Down Expand Up @@ -624,7 +624,7 @@ fn known_buffer_size_for_ffi_type(tpe: ffi::enum_field_types) -> Option<usize> {
t::MYSQL_TYPE_TIME
| t::MYSQL_TYPE_DATE
| t::MYSQL_TYPE_DATETIME
| t::MYSQL_TYPE_TIMESTAMP => Some(size_of::<MYSQL_TIME>()),
| t::MYSQL_TYPE_TIMESTAMP => Some(size_of::<MysqlTime>()),
_ => None,
}
}
Expand Down
11 changes: 11 additions & 0 deletions diesel/src/mysql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,24 @@
//! MySQL, you may need to work with this module directly.

pub(crate) mod backend;
#[cfg(feature = "mysql")]
mod connection;
mod value;

mod query_builder;
pub mod types;

pub use self::backend::{Mysql, MysqlType};
#[cfg(feature = "mysql")]
pub use self::connection::MysqlConnection;
pub use self::query_builder::MysqlQueryBuilder;
pub use self::value::{MysqlValue, NumericRepresentation};

/// Data structures for MysqSQL types which have no corresponding Rust type
///
/// Most of these types are used to implement `ToSql` and `FromSql` for higher
/// level types.
pub mod data_types {
#[doc(inline)]
pub use super::types::{MysqlTime, MysqlTimestampType};
}
139 changes: 120 additions & 19 deletions diesel/src/mysql/types/date_and_time.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,122 @@
#[cfg(feature = "chrono")]
use chrono::*;
use mysqlclient_sys as ffi;
use std::io::Write;
use std::os::raw as libc;
use std::{mem, slice};

use super::MYSQL_TIME;
use crate::deserialize::{self, FromSql};
use crate::mysql::{Mysql, MysqlValue};
use crate::serialize::{self, IsNull, Output, ToSql};
use crate::sql_types::{Date, Datetime, Time, Timestamp};

// This is a type from libmysqlclient
// we have our own copy here to not break the
// public API as soon as this type changes
// in the mysqlclient-sys dependency
/// Corresponding rust representation of the
/// [MYSQL_TIME](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html)
/// struct from libmysqlclient
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub struct MysqlTime {
/// [Year field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#af585231d3ed0bc2fa389856e61e15d4e)
pub year: libc::c_uint,
/// [Month field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#ad3e92bddbd9ccf2e50117bdd51c235a2)
pub month: libc::c_uint,
/// [Day field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#ad51088bd5ab4ddc02e62d778d71ed808)
pub day: libc::c_uint,
/// [Hour field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a7717a9c4de23a22863fe9c20b0706274)
pub hour: libc::c_uint,
/// [Minute field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#acfad0dafd22da03a527c58fdebfa9d14)
pub minute: libc::c_uint,
/// [Second field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a4cceb29d1a457f2ea961ce0d893814da)
pub second: libc::c_uint,
/// [Microseconds](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a2e0fddb071af25ff478d16dc5514ba71)
pub second_part: libc::c_ulong,
/// [Is this a negative timestamp](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#af13161fbff85e4fe0ec9cd49b6eac1b8)
pub neg: bool,
/// [Timestamp type](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a5331236f9b527a6e6b5f23d7c8058665)
pub time_type: MysqlTimestampType,
/// [Time zone displacement specified is seconds](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a07f3c8e1989c9805ba919d2120c8fed4)
pub time_zone_displacement: libc::c_int,
}

impl MysqlTime {
/// Construct a new instance of [MysqlTime]
#[allow(clippy::too_many_arguments)]
pub fn new(
year: libc::c_uint,
month: libc::c_uint,
day: libc::c_uint,
hour: libc::c_uint,
minute: libc::c_uint,
second: libc::c_uint,
second_part: libc::c_ulong,
neg: bool,
time_type: MysqlTimestampType,
time_zone_displacement: libc::c_int,
) -> Self {
Self {
year,
month,
day,
hour,
minute,
second,
second_part,
neg,
time_type,
time_zone_displacement,
}
}
}

// This is a type from libmysqlclient
// we have our own copy here to not break the
// public API as soon as this type changes
// in the mysqlclient-sys dependency
/// Rust representation of
/// [enum_mysql_timestamp_type](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73)
#[derive(PartialEq, Debug, Copy, Clone)]
#[repr(transparent)]
pub struct MysqlTimestampType(libc::c_int);

impl MysqlTimestampType {
/// Rust representation of
/// [MYSQL_TIMESTAMP_NONE](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73ace26c6b7d67a27c905dbcd130b3bd807)
pub const MYSQL_TIMESTAMP_NONE: MysqlTimestampType = MysqlTimestampType(-2);
/// Rust representation of
/// [MYSQL_TIMESTAMP_ERROR](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a3518624dcc1eaca8d816c52aa7528f72)
pub const MYSQL_TIMESTAMP_ERROR: MysqlTimestampType = MysqlTimestampType(-1);
/// Rust representation of
/// [MYSQL_TIMESTAMP_DATE](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a9e0845dc169b1f0056d2ffa3780c3f4e)
pub const MYSQL_TIMESTAMP_DATE: MysqlTimestampType = MysqlTimestampType(0);
/// Rust representation of
/// [MYSQL_TIMESTAMP_DATETIME](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a8f6d8f066ea6ea77280c6a0baf063ce1)
pub const MYSQL_TIMESTAMP_DATETIME: MysqlTimestampType = MysqlTimestampType(1);
/// Rust representation of
/// [MYSQL_TIMESTAMP_TIME](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a283c50fa3c62a2e17ad5173442edbbb9)
pub const MYSQL_TIMESTAMP_TIME: MysqlTimestampType = MysqlTimestampType(2);
/// Rust representation of
/// [MYSQL_TIMESTAMP_DATETIME_TZ](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a7afc91f565961eb5f3beebfebe7243a2)
pub const MYSQL_TIMESTAMP_DATETIME_TZ: MysqlTimestampType = MysqlTimestampType(3);
}

macro_rules! mysql_time_impls {
($ty:ty) => {
impl ToSql<$ty, Mysql> for MYSQL_TIME {
impl ToSql<$ty, Mysql> for MysqlTime {
fn to_sql<W: Write>(&self, out: &mut Output<W, Mysql>) -> serialize::Result {
let bytes = unsafe {
let bytes_ptr = self as *const MYSQL_TIME as *const u8;
slice::from_raw_parts(bytes_ptr, mem::size_of::<MYSQL_TIME>())
let bytes_ptr = self as *const MysqlTime as *const u8;
slice::from_raw_parts(bytes_ptr, mem::size_of::<MysqlTime>())
};
out.write_all(bytes)?;
Ok(IsNull::No)
}
}

impl FromSql<$ty, Mysql> for MYSQL_TIME {
impl FromSql<$ty, Mysql> for MysqlTime {
fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
value.time_value()
}
Expand All @@ -36,21 +129,24 @@ mysql_time_impls!(Timestamp);
mysql_time_impls!(Time);
mysql_time_impls!(Date);

#[cfg(feature = "chrono")]
impl ToSql<Datetime, Mysql> for NaiveDateTime {
fn to_sql<W: Write>(&self, out: &mut Output<W, Mysql>) -> serialize::Result {
<NaiveDateTime as ToSql<Timestamp, Mysql>>::to_sql(self, out)
}
}

#[cfg(feature = "chrono")]
impl FromSql<Datetime, Mysql> for NaiveDateTime {
fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
<NaiveDateTime as FromSql<Timestamp, Mysql>>::from_sql(bytes)
}
}

#[cfg(feature = "chrono")]
impl ToSql<Timestamp, Mysql> for NaiveDateTime {
fn to_sql<W: Write>(&self, out: &mut Output<W, Mysql>) -> serialize::Result {
let mysql_time = MYSQL_TIME {
let mysql_time = MysqlTime {
year: self.year() as libc::c_uint,
month: self.month() as libc::c_uint,
day: self.day() as libc::c_uint,
Expand All @@ -59,17 +155,18 @@ impl ToSql<Timestamp, Mysql> for NaiveDateTime {
second: self.second() as libc::c_uint,
second_part: libc::c_ulong::from(self.timestamp_subsec_micros()),
neg: false,
time_type: ffi::enum_mysql_timestamp_type::MYSQL_TIMESTAMP_DATETIME,
time_type: MysqlTimestampType::MYSQL_TIMESTAMP_DATETIME,
time_zone_displacement: 0,
};

<MYSQL_TIME as ToSql<Timestamp, Mysql>>::to_sql(&mysql_time, out)
<MysqlTime as ToSql<Timestamp, Mysql>>::to_sql(&mysql_time, out)
}
}

#[cfg(feature = "chrono")]
impl FromSql<Timestamp, Mysql> for NaiveDateTime {
fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
let mysql_time = <MYSQL_TIME as FromSql<Timestamp, Mysql>>::from_sql(bytes)?;
let mysql_time = <MysqlTime as FromSql<Timestamp, Mysql>>::from_sql(bytes)?;

NaiveDate::from_ymd_opt(
mysql_time.year as i32,
Expand All @@ -88,9 +185,10 @@ impl FromSql<Timestamp, Mysql> for NaiveDateTime {
}
}

#[cfg(feature = "chrono")]
impl ToSql<Time, Mysql> for NaiveTime {
fn to_sql<W: Write>(&self, out: &mut serialize::Output<W, Mysql>) -> serialize::Result {
let mysql_time = MYSQL_TIME {
let mysql_time = MysqlTime {
hour: self.hour() as libc::c_uint,
minute: self.minute() as libc::c_uint,
second: self.second() as libc::c_uint,
Expand All @@ -99,17 +197,18 @@ impl ToSql<Time, Mysql> for NaiveTime {
second_part: 0,
year: 0,
neg: false,
time_type: ffi::enum_mysql_timestamp_type::MYSQL_TIMESTAMP_TIME,
time_type: MysqlTimestampType::MYSQL_TIMESTAMP_TIME,
time_zone_displacement: 0,
};

<MYSQL_TIME as ToSql<Time, Mysql>>::to_sql(&mysql_time, out)
<MysqlTime as ToSql<Time, Mysql>>::to_sql(&mysql_time, out)
}
}

#[cfg(feature = "chrono")]
impl FromSql<Time, Mysql> for NaiveTime {
fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
let mysql_time = <MYSQL_TIME as FromSql<Time, Mysql>>::from_sql(bytes)?;
let mysql_time = <MysqlTime as FromSql<Time, Mysql>>::from_sql(bytes)?;
NaiveTime::from_hms_opt(
mysql_time.hour as u32,
mysql_time.minute as u32,
Expand All @@ -119,9 +218,10 @@ impl FromSql<Time, Mysql> for NaiveTime {
}
}

#[cfg(feature = "chrono")]
impl ToSql<Date, Mysql> for NaiveDate {
fn to_sql<W: Write>(&self, out: &mut Output<W, Mysql>) -> serialize::Result {
let mysql_time = MYSQL_TIME {
let mysql_time = MysqlTime {
year: self.year() as libc::c_uint,
month: self.month() as libc::c_uint,
day: self.day() as libc::c_uint,
Expand All @@ -130,17 +230,18 @@ impl ToSql<Date, Mysql> for NaiveDate {
second: 0,
second_part: 0,
neg: false,
time_type: ffi::enum_mysql_timestamp_type::MYSQL_TIMESTAMP_DATE,
time_type: MysqlTimestampType::MYSQL_TIMESTAMP_DATE,
time_zone_displacement: 0,
};

<MYSQL_TIME as ToSql<Date, Mysql>>::to_sql(&mysql_time, out)
<MysqlTime as ToSql<Date, Mysql>>::to_sql(&mysql_time, out)
}
}

#[cfg(feature = "chrono")]
impl FromSql<Date, Mysql> for NaiveDate {
fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
let mysql_time = <MYSQL_TIME as FromSql<Date, Mysql>>::from_sql(bytes)?;
let mysql_time = <MysqlTime as FromSql<Date, Mysql>>::from_sql(bytes)?;
NaiveDate::from_ymd_opt(
mysql_time.year as i32,
mysql_time.month as u32,
Expand All @@ -150,7 +251,7 @@ impl FromSql<Date, Mysql> for NaiveDate {
}
}

#[cfg(test)]
#[cfg(all(test, feature = "chrono"))]
mod tests {
extern crate chrono;
extern crate dotenv;
Expand Down
Loading

0 comments on commit 9cb852b

Please sign in to comment.