Repository: diesel-rs/diesel (language: rust)

Issue:
MultiConnect Timestamp (NaiveDateTime, PrimitiveDateTime, OffsetDateTime) not working.
<!--
If you want to report a bug, we added some points below which help us track down the problem faster.
-->

## Setup

Simple small program using the MultiConnect derive with the following schema and table.
```rust
pub mod schema {
    table! {
        posts (id) {
            id -> Integer,
            title -> Varchar,
            body -> Text,
            updated -> Timestamp,
        }
    }
}

pub mod models {
    use chrono::NaiveDateTime;

    use crate::schema::posts;
    #[derive(Queryable, Insertable)]
    pub struct Post {
        pub id: i32,
        pub title: String,
        pub body: String,
        pub updated: NaiveDateTime,
    }
}
```

### Versions

- **Rust:** rustc 1.73.0-nightly (180dffba1 2023-08-14)
- **Diesel:** master branch (c99ebda62395a092e059d6ca494861afa559028b)
- **Database:** MultiConnection (sqlite, postgresql, mysql)
- **Operating System:** Linux

### Feature Flags

- **diesel:** "chrono", "r2d2"

## Problem Description
When trying to use `Timestamp` via `NaiveDateTime` using the `MultiConnection` it reports there is no `ToSql`, and probably it will also complain there is no `FromSql`, but i haven't gotten that far yet.

### What are you trying to accomplish?
Using the `MultiConnection` derive feature using a single schema/table layout.

### What is the expected output?
No errors, and a way to be working with at least `NaiveDateTime`.

### What is the actual output?
Compile error.

```
error[E0277]: the trait bound `NaiveDateTime: ToSql<diesel::sql_types::Timestamp, multi_connection_impl::backend::MultiBackend>` is not satisfied
    --> src/main.rs:245:26
     |
245  |                 .execute(conn).expect("Error during inserting user");
     |                  ------- ^^^^ the trait `ToSql<diesel::sql_types::Timestamp, multi_connection_impl::backend::MultiBackend>` is not implemented for `NaiveDateTime`
     |                  |
     |                  required by a bound introduced by this call
     |
     = help: the following other types implement trait `ToSql<A, DB>`:
               <NaiveDateTime as ToSql<diesel::sql_types::Timestamp, Mysql>>
               <NaiveDateTime as ToSql<diesel::sql_types::Timestamp, Pg>>
               <NaiveDateTime as ToSql<diesel::sql_types::Timestamp, Sqlite>>
               <NaiveDateTime as ToSql<diesel::sql_types::Nullable<diesel::sql_types::Timestamp>, __DB>>
               <NaiveDateTime as ToSql<diesel::sql_types::Nullable<Datetime>, __DB>>
               <NaiveDateTime as ToSql<diesel::sql_types::Nullable<diesel::sql_types::Timestamptz>, __DB>>
               <NaiveDateTime as ToSql<Datetime, Mysql>>
               <NaiveDateTime as ToSql<diesel::sql_types::Timestamptz, Pg>>
               <NaiveDateTime as ToSql<TimestamptzSqlite, Sqlite>>
     = note: required for `diesel::expression::bound::Bound<diesel::sql_types::Timestamp, NaiveDateTime>` to implement `QueryFragment<multi_connection_impl::backend::MultiBackend>`
     = note: 1 redundant requirement hidden
     = note: required for `ColumnInsertValue<schema::posts::columns::updated, diesel::expression::bound::Bound<diesel::sql_types::Timestamp, NaiveDateTime>>` to implement `QueryFragment<multi_connection_impl::backend::MultiBackend>`
     = note: required for `ColumnInsertValue<schema::posts::columns::updated, diesel::expression::bound::Bound<diesel::sql_types::Timestamp, NaiveDateTime>>` to implement `InsertValues<schema::posts::table, multi_connection_impl::backend::MultiBackend>`
     = note: 3 redundant requirements hidden
     = note: required for `InsertStatement<table, ValuesClause<(ColumnInsertValue<title, Bound<Text, String>>, ColumnInsertValue<body, Bound<Text, String>>, ColumnInsertValue<published, Bound<Bool, bool>>, ColumnInsertValue<updated, Bound<Timestamp, NaiveDateTime>>), table>>` to implement `QueryFragment<multi_connection_impl::backend::MultiBackend>`
     = note: the full type name has been written to '/home/mathijs/rust/dieselmulticrate/target/debug/deps/dieselmulticrate-ddcbaeaecb4c0ddd.long-type-901884936185368146.txt'
     = note: required for `InsertStatement<table, ValuesClause<(ColumnInsertValue<title, Bound<Text, String>>, ColumnInsertValue<body, Bound<Text, String>>, ColumnInsertValue<published, Bound<Bool, bool>>, ColumnInsertValue<updated, Bound<Timestamp, NaiveDateTime>>), table>>` to implement `ExecuteDsl<InferConnection, multi_connection_impl::backend::MultiBackend>`
     = note: the full type name has been written to '/home/mathijs/rust/dieselmulticrate/target/debug/deps/dieselmulticrate-ddcbaeaecb4c0ddd.long-type-901884936185368146.txt'
note: required by a bound in `diesel::RunQueryDsl::execute`
    --> /home/mathijs/rust/diesel/diesel/src/query_dsl/mod.rs:1432:15
     |
1429 |     fn execute(self, conn: &mut Conn) -> QueryResult<usize>
     |        ------- required by a bound in this associated function
...
1432 |         Self: methods::ExecuteDsl<Conn>,
     | 
```

### Are you seeing any additional errors?
No (not  yet)

### Steps to reproduce

Use the schema/table layout from above.
And this is a create table for Postgresql as an example.
```sql
CREATE TABLE posts (
  id            INTEGER   NOT NULL PRIMARY KEY,
  title         TEXT      NOT NULL,
  body          TEXT      NOT NULL,
  updated       TIMESTAMP NOT NULL
);
```

<!--
Please include as much of your codebase as needed to reproduce the error.  If the relevant files are large, please consider linking to a public repository or a [Gist](https://gist.github.com/). This includes normally the following parts:

* The exact code where your hit the problem
* Relevant parts your schema, so any `table!` macro calls required for
* Any other type definitions involved in the code, which produces your problem
-->

## Checklist

- [x] I have already looked over the [issue tracker](https://github.com/diesel-rs/diesel/issues) and the [discussion forum](https://github.com/diesel-rs/diesel/discussions) for similar possible closed issues.
<!--
If you are unsure if your issue is a duplicate of an existing issue please link the issue in question here
--> 
- [x] This issue can be reproduced on Rust's stable channel. (Your issue will be
  closed if this is not the case)
- [x] This issue can be reproduced without requiring a third party crate

<!--
Thank you for your submission!  You're helping make Diesel more robust 🎉

We'll try to respond as quickly as possible.
-->



Discussion / hints:
Ok, i did some checking, and it basically is the same issues as it was with #3747.
It is just missing the correct from/to sql impl's generated via `generate_bind_collector`.

The issue i have is that I'm somehow unable to conditionally generate them if chrono is enabled or not.
Adding `chrono = []` to `diesel_derives` and `chrono = ["diesel_derives/chrono", "dep:chrono"]` doesn't seem to pass this feature on. Or something with `quote!` is not handling it for some reason.

If i just ignore the features and just add `use chrono::NaiveDateTime` to `mod multi_connection_impl` and add `(quote::quote!(diesel::sql_types::Timestamp), quote::quote!(NaiveDateTime))` to both the `to_sql` and `from_sql`, it seems to work for me.

Hopefully this makes fixing the issue a bit more easier :)  

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 322d62d727c7..051f715a1e2e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -221,7 +221,7 @@ jobs:
       - name: Test diesel-derives (nightly)
         if: matrix.rust == 'nightly'
         shell: bash
-        run: cargo +${{ matrix.rust }} test --manifest-path diesel_derives/Cargo.toml --no-default-features --features "diesel/${{ matrix.backend }} diesel/unstable"
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_derives/Cargo.toml --no-default-features --features "diesel/${{ matrix.backend }} diesel/unstable diesel/time time diesel/chrono chrono"
 
       - name: Test diesel-derives
         shell: bash
diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml
index ab0104486f3f..c66d2229e2aa 100644
--- a/diesel/Cargo.toml
+++ b/diesel/Cargo.toml
@@ -68,6 +68,8 @@ returning_clauses_for_sqlite_3_35 = []
 i-implement-a-third-party-backend-and-opt-into-breaking-changes = []
 nightly-error-messages = []
 r2d2 = ["diesel_derives/r2d2", "dep:r2d2"]
+chrono = ["diesel_derives/chrono", "dep:chrono"]
+time = ["diesel_derives/time", "dep:time"]
 
 [package.metadata.docs.rs]
 features = ["postgres", "mysql", "sqlite", "extras"]
diff --git a/diesel/src/internal/derives.rs b/diesel/src/internal/derives.rs
index be8929c8e486..216936cf6ac0 100644
--- a/diesel/src/internal/derives.rs
+++ b/diesel/src/internal/derives.rs
@@ -69,4 +69,12 @@ pub mod multiconnection {
 
     #[doc(hidden)]
     pub use crate::query_builder::select_statement::SelectStatementAccessor;
+
+    #[doc(hidden)]
+    #[cfg(feature = "chrono")]
+    pub use chrono;
+
+    #[doc(hidden)]
+    #[cfg(feature = "time")]
+    pub use time;
 }
diff --git a/diesel_derives/Cargo.toml b/diesel_derives/Cargo.toml
index 489592ad7f52..2fcf6f4425f1 100644
--- a/diesel_derives/Cargo.toml
+++ b/diesel_derives/Cargo.toml
@@ -44,3 +44,5 @@ mysql = []
 without-deprecated = []
 with-deprecated = []
 r2d2 = []
+chrono = []
+time = []
diff --git a/diesel_derives/src/multiconnection.rs b/diesel_derives/src/multiconnection.rs
index 1ec5c623c24d..d32c142c53c2 100644
--- a/diesel_derives/src/multiconnection.rs
+++ b/diesel_derives/src/multiconnection.rs
@@ -565,7 +565,7 @@ fn generate_row(connection_types: &[ConnectionVariant]) -> TokenStream {
 }
 
 fn generate_bind_collector(connection_types: &[ConnectionVariant]) -> TokenStream {
-    let to_sql_impls = vec![
+    let mut to_sql_impls = vec![
         (
             quote::quote!(diesel::sql_types::SmallInt),
             quote::quote!(i16),
@@ -583,11 +583,40 @@ fn generate_bind_collector(connection_types: &[ConnectionVariant]) -> TokenStrea
             quote::quote!([u8]),
         ),
         (quote::quote!(diesel::sql_types::Bool), quote::quote!(bool)),
-    ]
-    .into_iter()
-    .map(|t| generate_to_sql_impls(t, connection_types));
+    ];
+    if cfg!(feature = "chrono") {
+        to_sql_impls.push((
+            quote::quote!(diesel::sql_types::Timestamp),
+            quote::quote!(diesel::internal::derives::multiconnection::chrono::NaiveDateTime),
+        ));
+        to_sql_impls.push((
+            quote::quote!(diesel::sql_types::Date),
+            quote::quote!(diesel::internal::derives::multiconnection::chrono::NaiveDate),
+        ));
+        to_sql_impls.push((
+            quote::quote!(diesel::sql_types::Time),
+            quote::quote!(diesel::internal::derives::multiconnection::chrono::NaiveTime),
+        ));
+    }
+    if cfg!(feature = "time") {
+        to_sql_impls.push((
+            quote::quote!(diesel::sql_types::Timestamp),
+            quote::quote!(diesel::internal::derives::multiconnection::time::PrimitiveDateTime),
+        ));
+        to_sql_impls.push((
+            quote::quote!(diesel::sql_types::Time),
+            quote::quote!(diesel::internal::derives::multiconnection::time::Time),
+        ));
+        to_sql_impls.push((
+            quote::quote!(diesel::sql_types::Date),
+            quote::quote!(diesel::internal::derives::multiconnection::time::Date),
+        ));
+    }
+    let to_sql_impls = to_sql_impls
+        .into_iter()
+        .map(|t| generate_to_sql_impls(t, connection_types));
 
-    let from_sql_impls = vec![
+    let mut from_sql_impls = vec![
         (
             quote::quote!(diesel::sql_types::SmallInt),
             quote::quote!(i16),
@@ -608,9 +637,36 @@ fn generate_bind_collector(connection_types: &[ConnectionVariant]) -> TokenStrea
             quote::quote!(Vec<u8>),
         ),
         (quote::quote!(diesel::sql_types::Bool), quote::quote!(bool)),
-    ]
-    .into_iter()
-    .map(generate_from_sql_impls);
+    ];
+    if cfg!(feature = "chrono") {
+        from_sql_impls.push((
+            quote::quote!(diesel::sql_types::Timestamp),
+            quote::quote!(diesel::internal::derives::multiconnection::chrono::NaiveDateTime),
+        ));
+        from_sql_impls.push((
+            quote::quote!(diesel::sql_types::Date),
+            quote::quote!(diesel::internal::derives::multiconnection::chrono::NaiveDate),
+        ));
+        from_sql_impls.push((
+            quote::quote!(diesel::sql_types::Time),
+            quote::quote!(diesel::internal::derives::multiconnection::chrono::NaiveTime),
+        ));
+    }
+    if cfg!(feature = "time") {
+        from_sql_impls.push((
+            quote::quote!(diesel::sql_types::Timestamp),
+            quote::quote!(diesel::internal::derives::multiconnection::time::PrimitiveDateTime),
+        ));
+        from_sql_impls.push((
+            quote::quote!(diesel::sql_types::Time),
+            quote::quote!(diesel::internal::derives::multiconnection::time::Time),
+        ));
+        from_sql_impls.push((
+            quote::quote!(diesel::sql_types::Date),
+            quote::quote!(diesel::internal::derives::multiconnection::time::Date),
+        ));
+    }
+    let from_sql_impls = from_sql_impls.into_iter().map(generate_from_sql_impls);
 
     let into_bind_value_bounds = connection_types.iter().map(|c| {
         let ty = c.ty;


Test patch:
diff --git a/diesel_derives/tests/multiconnection.rs b/diesel_derives/tests/multiconnection.rs
index 87537d039c13..51c93836d116 100644
--- a/diesel_derives/tests/multiconnection.rs
+++ b/diesel_derives/tests/multiconnection.rs
@@ -1,6 +1,5 @@
 use crate::schema::users;
 use diesel::prelude::*;
-use diesel::sql_types::{Binary, Float, Integer, Nullable, Text};
 
 #[derive(diesel::MultiConnection)]
 pub enum InferConnection {
@@ -20,16 +19,7 @@ pub struct User {
 
 #[test]
 fn check_queries_work() {
-    let database_url = if cfg!(feature = "mysql") {
-        dotenvy::var("MYSQL_UNIT_TEST_DATABASE_URL").or_else(|_| dotenvy::var("DATABASE_URL"))
-    } else if cfg!(feature = "postgres") {
-        dotenvy::var("PG_DATABASE_URL").or_else(|_| dotenvy::var("DATABASE_URL"))
-    } else {
-        Ok(dotenvy::var("DATABASE_URL").unwrap_or_else(|_| ":memory:".to_owned()))
-    };
-    let database_url = database_url.expect("DATABASE_URL must be set in order to run tests");
-
-    let mut conn = InferConnection::establish(&database_url).unwrap();
+    let mut conn = establish_connection();
 
     diesel::sql_query(
         "CREATE TEMPORARY TABLE users(\
@@ -106,19 +96,325 @@ fn check_queries_work() {
 
     // delete
     diesel::delete(users::table).execute(&mut conn).unwrap();
+}
 
-    // more binds
-    // mostly nullable types
-    let (string, int, blob, float) = diesel::select((
-        None::<String>.into_sql::<Nullable<Text>>(),
-        None::<i32>.into_sql::<Nullable<Integer>>(),
-        None::<f32>.into_sql::<Nullable<Float>>(),
-        None::<Vec<u8>>.into_sql::<Nullable<Binary>>(),
-    ))
-    .get_result::<(Option<String>, Option<i32>, Option<f32>, Option<Vec<u8>>)>(&mut conn)
-    .unwrap();
-    assert!(string.is_none());
-    assert!(int.is_none());
-    assert!(float.is_none());
-    assert!(blob.is_none());
+fn establish_connection() -> InferConnection {
+    let database_url = if cfg!(feature = "mysql") {
+        dotenvy::var("MYSQL_UNIT_TEST_DATABASE_URL").or_else(|_| dotenvy::var("DATABASE_URL"))
+    } else if cfg!(feature = "postgres") {
+        dotenvy::var("PG_DATABASE_URL").or_else(|_| dotenvy::var("DATABASE_URL"))
+    } else {
+        Ok(dotenvy::var("DATABASE_URL").unwrap_or_else(|_| ":memory:".to_owned()))
+    };
+    let database_url = database_url.expect("DATABASE_URL must be set in order to run tests");
+
+    InferConnection::establish(&database_url).unwrap()
+}
+
+#[cfg(all(feature = "chrono", feature = "time"))]
+fn make_test_table(conn: &mut InferConnection) {
+    match conn {
+        #[cfg(feature = "postgres")]
+        InferConnection::Pg(ref mut conn) => {
+            diesel::sql_query(
+                "CREATE TEMPORARY TABLE type_test( \
+                     small_int SMALLINT,\
+                     integer INTEGER,\
+                     big_int BIGINT,\
+                     float FLOAT4,\
+                     double FLOAT8,\
+                     string TEXT,\
+                     blob BYTEA,\
+                     timestamp1 TIMESTAMP,\
+                     date1 DATE,\
+                     time1 TIME,\
+                     timestamp2 TIMESTAMP,\
+                     date2 DATE,\
+                     time2 TIME
+                 )",
+            )
+            .execute(conn)
+            .unwrap();
+        }
+        #[cfg(feature = "sqlite")]
+        InferConnection::Sqlite(ref mut conn) => {
+            diesel::sql_query(
+                "CREATE TEMPORARY TABLE type_test( \
+                     small_int SMALLINT,\
+                     integer INTEGER,\
+                     big_int BIGINT,\
+                     float FLOAT4,\
+                     double FLOAT8,\
+                     string TEXT,\
+                     blob BLOB,\
+                     timestamp1 TIMESTAMP,\
+                     date1 DATE,\
+                     time1 TIME,\
+                     timestamp2 TIMESTAMP,\
+                     date2 DATE,\
+                     time2 TIME
+                 )",
+            )
+            .execute(conn)
+            .unwrap();
+        }
+        #[cfg(feature = "mysql")]
+        InferConnection::Mysql(ref mut conn) => {
+            diesel::sql_query(
+                "CREATE TEMPORARY TABLE type_test( \
+                     `small_int` SMALLINT,\
+                     `integer` INT,\
+                     `big_int` BIGINT,\
+                     `float` FLOAT,\
+                     `double` DOUBLE,\
+                     `string` TEXT,\
+                     `blob` BLOB,\
+                     `timestamp1` DATETIME,
+                     `date1` DATE,\
+                     `time1` TIME,\
+                     `timestamp2` DATETIME,
+                     `date2` DATE,\
+                     `time2` TIME
+                 )",
+            )
+            .execute(conn)
+            .unwrap();
+        }
+    }
+}
+
+#[cfg(all(feature = "chrono", feature = "time"))]
+#[test]
+fn type_checks() {
+    use diesel::internal::derives::multiconnection::{chrono, time};
+
+    table! {
+        type_test(integer) {
+            small_int -> SmallInt,
+            integer -> Integer,
+            big_int -> BigInt,
+            float -> Float,
+            double -> Double,
+            string -> Text,
+            blob -> Blob,
+            timestamp1 -> Timestamp,
+            time1 -> Time,
+            date1 -> Date,
+            timestamp2 -> Timestamp,
+            time2 -> Time,
+            date2 -> Date,
+        }
+    }
+
+    let mut conn = establish_connection();
+    make_test_table(&mut conn);
+    conn.begin_test_transaction().unwrap();
+    let small_int = 1_i16;
+    let integer = 2_i32;
+    let big_int = 3_i64;
+    let float = 4.0_f32;
+    let double = 5.0_f64;
+    let string = String::from("bar");
+    let blob = vec![1_u8, 2, 3, 4];
+    let date1 = chrono::NaiveDate::from_ymd_opt(2023, 08, 17).unwrap();
+    let time1 = chrono::NaiveTime::from_hms_opt(07, 50, 12).unwrap();
+    let timestamp1 = chrono::NaiveDateTime::new(date1, time1);
+    let time2 = time::Time::from_hms(12, 22, 23).unwrap();
+    let date2 = time::Date::from_calendar_date(2023, time::Month::August, 26).unwrap();
+    let timestamp2 = time::PrimitiveDateTime::new(date2, time2);
+
+    diesel::insert_into(type_test::table)
+        .values((
+            type_test::small_int.eq(small_int),
+            type_test::integer.eq(integer),
+            type_test::big_int.eq(big_int),
+            type_test::float.eq(float),
+            type_test::double.eq(double),
+            type_test::string.eq(&string),
+            type_test::blob.eq(&blob),
+            type_test::timestamp1.eq(timestamp1),
+            type_test::time1.eq(time1),
+            type_test::date1.eq(date1),
+            type_test::timestamp2.eq(timestamp2),
+            type_test::time2.eq(time2),
+            type_test::date2.eq(date2),
+        ))
+        .execute(&mut conn)
+        .unwrap();
+
+    let result = type_test::table
+        .get_result::<(
+            i16,                     //0
+            i32,                     //1
+            i64,                     //2
+            f32,                     //3
+            f64,                     //4
+            String,                  //5
+            Vec<u8>,                 //6
+            chrono::NaiveDateTime,   //7
+            chrono::NaiveTime,       //8
+            chrono::NaiveDate,       //9
+            time::PrimitiveDateTime, //10
+            time::Time,              //11
+            time::Date,              //12
+        )>(&mut conn)
+        .unwrap();
+
+    assert_eq!(small_int, result.0);
+    assert_eq!(integer, result.1);
+    assert_eq!(big_int, result.2);
+    assert_eq!(float, result.3);
+    assert_eq!(double, result.4);
+    assert_eq!(string, result.5);
+    assert_eq!(blob, result.6);
+    assert_eq!(timestamp1, result.7);
+    assert_eq!(time1, result.8);
+    assert_eq!(date1, result.9);
+    assert_eq!(timestamp2, result.10);
+    assert_eq!(time2, result.11);
+    assert_eq!(date2, result.12);
+}
+
+#[cfg(all(feature = "chrono", feature = "time"))]
+#[test]
+fn nullable_type_checks() {
+    use diesel::internal::derives::multiconnection::{chrono, time};
+
+    table! {
+        type_test(integer) {
+            small_int -> Nullable<SmallInt>,
+            integer -> Nullable<Integer>,
+            big_int -> Nullable<BigInt>,
+            float -> Nullable<Float>,
+            double -> Nullable<Double>,
+            string -> Nullable<Text>,
+            blob -> Nullable<Blob>,
+            timestamp1 -> Nullable<Timestamp>,
+            time1 -> Nullable<Time>,
+            date1 -> Nullable<Date>,
+            timestamp2 -> Nullable<Timestamp>,
+            time2 -> Nullable<Time>,
+            date2 -> Nullable<Date>,
+        }
+    }
+
+    let mut conn = establish_connection();
+    make_test_table(&mut conn);
+    conn.begin_test_transaction().unwrap();
+
+    let small_int = Some(1_i16);
+    let integer = Some(2_i32);
+    let big_int = Some(3_i64);
+    let float = Some(4.0_f32);
+    let double = Some(5.0_f64);
+    let string = Some(String::from("bar"));
+    let blob = Some(vec![1_u8, 2, 3, 4]);
+    let date1 = Some(chrono::NaiveDate::from_ymd_opt(2023, 08, 17).unwrap());
+    let time1 = Some(chrono::NaiveTime::from_hms_opt(07, 50, 12).unwrap());
+    let timestamp1 = Some(chrono::NaiveDateTime::new(date1.unwrap(), time1.unwrap()));
+    let time2 = Some(time::Time::from_hms(12, 22, 23).unwrap());
+    let date2 = Some(time::Date::from_calendar_date(2023, time::Month::August, 26).unwrap());
+    let timestamp2 = Some(time::PrimitiveDateTime::new(date2.unwrap(), time2.unwrap()));
+
+    diesel::insert_into(type_test::table)
+        .values((
+            type_test::small_int.eq(small_int),
+            type_test::integer.eq(integer),
+            type_test::big_int.eq(big_int),
+            type_test::float.eq(float),
+            type_test::double.eq(double),
+            type_test::string.eq(&string),
+            type_test::blob.eq(&blob),
+            type_test::timestamp1.eq(timestamp1),
+            type_test::time1.eq(time1),
+            type_test::date1.eq(date1),
+            type_test::timestamp2.eq(timestamp2),
+            type_test::time2.eq(time2),
+            type_test::date2.eq(date2),
+        ))
+        .execute(&mut conn)
+        .unwrap();
+
+    let result = type_test::table
+        .get_result::<(
+            Option<i16>,
+            Option<i32>,
+            Option<i64>,
+            Option<f32>,
+            Option<f64>,
+            Option<String>,
+            Option<Vec<u8>>,
+            Option<chrono::NaiveDateTime>,
+            Option<chrono::NaiveTime>,
+            Option<chrono::NaiveDate>,
+            Option<time::PrimitiveDateTime>,
+            Option<time::Time>,
+            Option<time::Date>,
+        )>(&mut conn)
+        .unwrap();
+
+    assert_eq!(small_int, result.0);
+    assert_eq!(integer, result.1);
+    assert_eq!(big_int, result.2);
+    assert_eq!(float, result.3);
+    assert_eq!(double, result.4);
+    assert_eq!(string, result.5);
+    assert_eq!(blob, result.6);
+    assert_eq!(timestamp1, result.7);
+    assert_eq!(time1, result.8);
+    assert_eq!(date1, result.9);
+    assert_eq!(timestamp2, result.10);
+    assert_eq!(time2, result.11);
+    assert_eq!(date2, result.12);
+
+    diesel::delete(type_test::table).execute(&mut conn).unwrap();
+
+    diesel::insert_into(type_test::table)
+        .values((
+            type_test::small_int.eq(None::<i16>),
+            type_test::integer.eq(None::<i32>),
+            type_test::big_int.eq(None::<i64>),
+            type_test::float.eq(None::<f32>),
+            type_test::double.eq(None::<f64>),
+            type_test::string.eq(None::<String>),
+            type_test::blob.eq(None::<Vec<u8>>),
+            type_test::timestamp1.eq(None::<chrono::NaiveDateTime>),
+            type_test::time1.eq(None::<chrono::NaiveTime>),
+            type_test::date1.eq(None::<chrono::NaiveDate>),
+            type_test::timestamp2.eq(None::<time::PrimitiveDateTime>),
+            type_test::time2.eq(None::<time::Time>),
+            type_test::date2.eq(None::<time::Date>),
+        ))
+        .execute(&mut conn)
+        .unwrap();
+    let result = type_test::table
+        .get_result::<(
+            Option<i16>,
+            Option<i32>,
+            Option<i64>,
+            Option<f32>,
+            Option<f64>,
+            Option<String>,
+            Option<Vec<u8>>,
+            Option<chrono::NaiveDateTime>,
+            Option<chrono::NaiveTime>,
+            Option<chrono::NaiveDate>,
+            Option<time::PrimitiveDateTime>,
+            Option<time::Time>,
+            Option<time::Date>,
+        )>(&mut conn)
+        .unwrap();
+    assert!(result.0.is_none());
+    assert!(result.1.is_none());
+    assert!(result.2.is_none());
+    assert!(result.3.is_none());
+    assert!(result.4.is_none());
+    assert!(result.5.is_none());
+    assert!(result.6.is_none());
+    assert!(result.7.is_none());
+    assert!(result.8.is_none());
+    assert!(result.9.is_none());
+    assert!(result.10.is_none());
+    assert!(result.11.is_none());
+    assert!(result.12.is_none());
 }