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

Issue:
sqlite3 foreign keys which don't name columns can't be inferred
<!--
If you want to report a bug, we added some points below you can fill out. If you want to request a feature, feel free to remove all the irrelevant text. In addition to this [issue tracker](https://github.com/diesel-rs/diesel/issues), you can also talk to Diesel maintainers and users on [Gitter](https://gitter.im/diesel-rs/diesel).
-->

## Setup

### Versions

- **Rust:** `rustc 1.25.0-nightly (616b66dca 2018-02-02)`
- **Diesel:** `diesel 1.1.0`
- **Database:** `sqlite3 3.16.0 2016-11-04 19:09:39 0e5ffd9123d6d2d2b8f3701e8a73cc98a3a7ff5f`
- **Operating System** macOS 10.12.6 (16G1114)

### Feature Flags

- **diesel:** `sqlite postgres`

## Problem Description

Running `diesel print-schema` fails, with very terse output:

```
$ RUST_BACKTRACE=full RUST_LOG=trace diesel print-schema
Unexpected null for non-null column
```

### Steps to reproduce

```
sqlite> .schema accounts
CREATE TABLE accounts (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  account TEXT NOT NULL,
  data_center_id INTEGER NOT NULL,
  auth_key BLOB NOT NULL,
  UNIQUE (account, data_center_id),
  FOREIGN KEY (data_center_id) REFERENCES data_centers
);
sqlite> .schema data_centers
CREATE TABLE data_centers (
  id INTEGER PRIMARY KEY
);
```

This produces: 

```
sqlite> PRAGMA FOREIGN_KEY_LIST('accounts');
id          seq         table         from            to          on_update   on_delete   match
----------  ----------  ------------  --------------  ----------  ----------  ----------  ----------
0           0           data_centers  data_center_id  -NULL-      NO ACTION   NO ACTION   NONE
```

`to` is `NULL` because `REFERENCES data_centers` doesn't name any columns; it's implicitly the same as `REFERENCES data_centers(id)`. I'm pretty sure this is due to the `pragma_foreign_key_list` pseudo-table doesn't expect a `NULL`.

https://github.com/diesel-rs/diesel/blob/07319d363aff713dbe52914aa2f512431f559864/diesel_infer_schema/infer_schema_internals/src/sqlite.rs#L27-L38

<!--
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/).

Please post as much of your database schema as necessary. If you are using `infer_schema!`, you can use `diesel print-schema` and post the relevant parts from that.
-->

## Checklist

- [X] I have already looked over the [issue tracker](https://github.com/diesel-rs/diesel/issues) for similar issues.


<!--
Thank you for your submission!  You're helping make Diesel more robust 🎉

We'll try to respond as quickly as possible.
-->



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d123063de725..7ead1e69a92b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -24,7 +24,7 @@ jobs:
       matrix:
         rust: ["stable", "beta", "nightly"]
         backend: ["postgres", "sqlite", "mysql"]
-        os: [ubuntu-latest, macos-latest, windows-latest]
+        os: [ubuntu-latest, macos-latest, windows-2019]
     runs-on: ${{ matrix.os }}
     steps:
       - name: Checkout sources
@@ -153,13 +153,7 @@ jobs:
         run: |
           choco install sqlite
           cd /D C:\ProgramData\chocolatey\lib\SQLite\tools
-          dir "C:\Program Files\Microsoft Visual Studio"
-          dir "C:\Program Files\Microsoft Visual Studio\2022"
-          dir "C:\Program Files\Microsoft Visual Studio\2022\Enterprise"
-          dir "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC"
-          dir "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary"
-          dir "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build"
-          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
           lib /machine:x64 /def:sqlite3.def /out:sqlite3.lib
 
       - name: Set variables for sqlite (Windows)
@@ -324,7 +318,7 @@ jobs:
       - uses: actions/checkout@v3
       - uses: actions-rs/toolchain@v1
         with:
-          toolchain: 1.54.0
+          toolchain: 1.56.0
           profile: minimal
           override: true
       - name: Cache cargo registry
@@ -353,7 +347,7 @@ jobs:
       - uses: actions/checkout@v3
       - uses: actions-rs/toolchain@v1
         with:
-          toolchain: 1.54.0
+          toolchain: 1.57.0
           profile: minimal
           components: clippy, rustfmt
           override: true
@@ -369,6 +363,11 @@ jobs:
         run: |
           sudo apt-get update
           sudo apt-get -y install libsqlite3-dev libpq-dev libmysqlclient-dev
+      - name: Set environment variables
+        shell: bash
+        run: |
+          echo "RUSTFLAGS=-D warnings" >> $GITHUB_ENV
+          echo "RUSTDOCFLAGS=-D warnings" >> $GITHUB_ENV
 
       - name: Remove potential newer clippy.toml from dependencies
         run: |
@@ -377,10 +376,46 @@ jobs:
           find ~/.cargo/registry -iname "*clippy.toml" -delete
 
       - name: Run clippy
-        uses: actions-rs/cargo@v1
-        with:
-          command: clippy
-          args: --all
+        run: |
+          cargo clippy --tests --manifest-path diesel_derives/Cargo.toml --features "postgres diesel/postgres"
+          cargo clippy --tests --manifest-path diesel/Cargo.toml --features "postgres"
+          cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "postgres diesel/postgres"
+          cargo clippy --tests --manifest-path diesel_migrations/migrations_internals/Cargo.toml
+          cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "postgres diesel/postgres"
+          cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "postgres diesel/postgres"
+          cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "postgres" --no-default-features
+          cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "postgres"
+          cargo clippy --tests --manifest-path examples/postgres/getting_started_step_1/Cargo.toml
+          cargo clippy --tests --manifest-path examples/postgres/getting_started_step_2/Cargo.toml
+          cargo clippy --tests --manifest-path examples/postgres/getting_started_step_3/Cargo.toml
+          cargo clippy --tests --manifest-path examples/postgres/advanced-blog-cli/Cargo.toml
+          cargo clippy --tests --manifest-path examples/postgres/all_about_inserts/Cargo.toml
+          cargo clippy --tests --manifest-path examples/postgres/all_about_updates/Cargo.toml
+          cargo clippy --tests --manifest-path examples/postgres/custom_types/Cargo.toml
+
+          cargo clippy --tests --manifest-path diesel_derives/Cargo.toml --features "sqlite diesel/sqlite"
+          cargo clippy --tests --manifest-path diesel/Cargo.toml --features "sqlite"
+          cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "sqlite diesel/sqlite"
+          cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "sqlite diesel/sqlite"
+          cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "sqlite diesel/sqlite"
+          cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "sqlite" --no-default-features
+          cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "sqlite"
+          cargo clippy --tests --manifest-path examples/sqlite/getting_started_step_1/Cargo.toml
+          cargo clippy --tests --manifest-path examples/sqlite/getting_started_step_2/Cargo.toml
+          cargo clippy --tests --manifest-path examples/sqlite/getting_started_step_3/Cargo.toml
+          cargo clippy --tests --manifest-path examples/sqlite/all_about_inserts/Cargo.toml
+
+          cargo clippy --tests --manifest-path diesel_derives/Cargo.toml --features "mysql diesel/mysql"
+          cargo clippy --tests --manifest-path diesel/Cargo.toml --features "mysql"
+          cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "mysql diesel/mysql"
+          cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "mysql diesel/mysql"
+          cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "mysql diesel/mysql"
+          cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "mysql" --no-default-features
+          cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "mysql"
+          cargo clippy --tests --manifest-path examples/mysql/getting_started_step_1/Cargo.toml
+          cargo clippy --tests --manifest-path examples/mysql/getting_started_step_2/Cargo.toml
+          cargo clippy --tests --manifest-path examples/mysql/getting_started_step_3/Cargo.toml
+          cargo clippy --tests --manifest-path examples/mysql/all_about_inserts/Cargo.toml
 
       - name: Check formating
         uses: actions-rs/cargo@v1
@@ -427,13 +462,13 @@ jobs:
         run: cargo -Z build-std test --manifest-path diesel/Cargo.toml --no-default-features --features "sqlite extras libsqlite3-sys libsqlite3-sys/bundled libsqlite3-sys/with-asan" --target x86_64-unknown-linux-gnu
 
   minimal_rust_version:
-    name: Check Minimal supported rust version (1.54.0)
+    name: Check Minimal supported rust version (1.56.0)
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
       - uses: actions-rs/toolchain@v1
         with:
-          toolchain: 1.54.0
+          toolchain: 1.56.0
           profile: minimal
           override: true
       - name: Cache cargo registry
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7b31193b4632..78a5d08f2653 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,7 +8,28 @@ default features enabled using some set of dependencies. Those set of dependenci
 an up to date version of the specific dependency. We check this by using the unstable `-Z minimal-version` cargo flag. 
 Increasing the minimal supported Rust version will always be coupled at least with a minor release.
 
-## Unreleased
+## [2.0.0 Rc1] 2022-07-19 
+
+### Changed
+
+* We've changed the `RunQueryDsl::load_iter` interface to support different
+loading modes. This enables us to support more than one strategy for loading 
+values by iterator from the database. 
+
+### Added
+
+* Adds an `ipnet-address` feature flag, allowing support (de)serializing IP
+  values from the database using types provided by `ipnet`. This feature
+  may be enabled concurrently with the previously existing `network-address`
+  feature.
+* We've added support for loading values using libpq's row-by-row mode via 
+the new iterator interface
+
+### Fixed
+
+* Updated `ipnetwork` to allow version 0.20.
+* Updated `libsqlite3-sys` to allow version 0.25
+* Fix a bug that prevents connection reusing with r2d2 
 
 ## [2.0.0 Rc0] 2022-04-22
 
@@ -109,7 +130,7 @@ Increasing the minimal supported Rust version will always be coupled at least wi
 
 ### Changed
 
-* The minimal officially supported rustc version is now 1.54.0
+* The minimal officially supported rustc version is now 1.56.0
 
 * Interacting with a database requires a mutable connection.
 
diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml
index 78341f1eba8e..6e0603e42daa 100644
--- a/diesel/Cargo.toml
+++ b/diesel/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "diesel"
-version = "2.0.0-rc.0"
+version = "2.0.0-rc.1"
 license = "MIT OR Apache-2.0"
 description = "A safe, extensible ORM and Query Builder for PostgreSQL, SQLite, and MySQL"
 readme = "README.md"
@@ -10,13 +10,13 @@ repository = "https://github.com/diesel-rs/diesel"
 keywords = ["orm", "database", "sql"]
 categories = ["database"]
 edition = "2018"
-rust-version = "1.54.0"
+rust-version = "1.56.0"
 
 [dependencies]
 byteorder = { version = "1.0", optional = true }
 chrono = { version = "0.4.19", optional = true, default-features = false, features = ["clock", "std"] }
 libc = { version = "0.2.0", optional = true }
-libsqlite3-sys = { version = ">=0.17.2, <0.25.0", optional = true, features = ["bundled_bindings"] }
+libsqlite3-sys = { version = ">=0.17.2, <0.26.0", optional = true, features = ["bundled_bindings"] }
 mysqlclient-sys = { version = "0.2.5", optional = true }
 pq-sys = { version = "0.4.0", optional = true }
 quickcheck = { version = "1.0.3", optional = true }
@@ -24,7 +24,8 @@ serde_json = { version = ">=0.8.0, <2.0", optional = true }
 url = { version = "2.1.0", optional = true }
 percent-encoding = { version = "2.1.0", optional = true }
 uuid = { version = ">=0.7.0, <2.0.0", optional = true }
-ipnetwork = { version = ">=0.12.2, <0.19.0", optional = true }
+ipnetwork = { version = ">=0.12.2, <0.21.0", optional = true }
+ipnet = { version = "2.5.0", optional = true }
 num-bigint = { version = ">=0.2.0, <0.5.0", optional = true }
 num-traits = { version = "0.2.0", optional = true }
 num-integer = { version = "0.1.39", optional = true }
@@ -34,13 +35,13 @@ r2d2 = { version = ">= 0.8.2, < 0.9.0", optional = true }
 itoa = { version = "1.0.0", optional = true }
 
 [dependencies.diesel_derives]
-version = "~2.0.0-rc.0"
+version = "~2.0.0-rc.1"
 path = "../diesel_derives"
 
 [dev-dependencies]
 cfg-if = "1"
 dotenvy = "0.15"
-ipnetwork = ">=0.12.2, <0.19.0"
+ipnetwork = ">=0.12.2, <0.21.0"
 quickcheck = "1.0.3"
 
 [features]
@@ -58,6 +59,7 @@ mysql = ["mysqlclient-sys", "url", "percent-encoding", "bitflags", "mysql_backen
 without-deprecated = ["diesel_derives/without-deprecated"]
 with-deprecated = ["diesel_derives/with-deprecated"]
 network-address = ["ipnetwork", "libc"]
+ipnet-address = ["ipnet", "libc"]
 numeric = ["num-bigint", "bigdecimal", "num-traits", "num-integer"]
 postgres_backend = ["diesel_derives/postgres", "bitflags", "byteorder", "itoa"]
 mysql_backend = ["diesel_derives/mysql", "byteorder"]
diff --git a/diesel/src/backend.rs b/diesel/src/backend.rs
index 07efb81f700e..93e4bdc2e90d 100644
--- a/diesel/src/backend.rs
+++ b/diesel/src/backend.rs
@@ -142,7 +142,10 @@ pub type BindCollector<'a, DB> = <DB as HasBindCollector<'a>>::BindCollector;
 /// a custom `QueryFragment<YourBackend, YourSpecialSyntaxType>` implementation
 /// to specialize on generic `QueryFragment<DB, DB::AssociatedType>` implementations.
 ///
-/// See the [`sql_dialect`] module for options provided by diesel out of the box.
+#[cfg_attr(
+    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+    doc = "See the [`sql_dialect`] module for options provided by diesel out of the box."
+)]
 pub trait SqlDialect: self::private::TrustedBackend {
     /// Configures how this backends supports `RETURNING` clauses
     ///
@@ -157,13 +160,19 @@ pub trait SqlDialect: self::private::TrustedBackend {
         doc = "implementation for `ReturningClause`"
     )]
     ///
-    /// See [`sql_dialect::returning_clause`] for provided default implementations
+    #[cfg_attr(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+        doc = "See [`sql_dialect::returning_clause`] for provided default implementations"
+    )]
     type ReturningClause;
     /// Configures how this backend supports `ON CONFLICT` clauses
     ///
     /// This allows backends to opt in `ON CONFLICT` clause support
     ///
-    /// See [`sql_dialect::on_conflict_clause`] for provided default implementations
+    #[cfg_attr(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+        doc = "See [`sql_dialect::on_conflict_clause`] for provided default implementations"
+    )]
     type OnConflictClause;
     /// Configures how this backend handles the bare `DEFAULT` keyword for
     /// inserting the default value in a `INSERT INTO` `VALUES` clause
@@ -171,7 +180,10 @@ pub trait SqlDialect: self::private::TrustedBackend {
     /// This allows backends to opt in support for `DEFAULT` value expressions
     /// for insert statements
     ///
-    /// See [`sql_dialect::default_keyword_for_insert`] for provided default implementations
+    #[cfg_attr(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+        doc = "See [`sql_dialect::default_keyword_for_insert`] for provided default implementations"
+    )]
     type InsertWithDefaultKeyword;
     /// Configures how this backend handles Batch insert statements
     ///
@@ -185,7 +197,10 @@ pub trait SqlDialect: self::private::TrustedBackend {
         doc = "implementation for `BatchInsert`"
     )]
     ///
-    /// See [`sql_dialect::batch_insert_support`] for provided default implementations
+    #[cfg_attr(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+        doc = "See [`sql_dialect::batch_insert_support`] for provided default implementations"
+    )]
     type BatchInsertSupport;
     /// Configures how this backend handles the `DEFAULT VALUES` clause for
     /// insert statements.
@@ -200,7 +215,10 @@ pub trait SqlDialect: self::private::TrustedBackend {
         doc = "implementation for `DefaultValues`"
     )]
     ///
-    /// See [`sql_dialect::default_value_clause`] for provided default implementations
+    #[cfg_attr(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+        doc = "See [`sql_dialect::default_value_clause`] for provided default implementations"
+    )]
     type DefaultValueClauseForInsert;
     /// Configures how this backend handles empty `FROM` clauses for select statements.
     ///
@@ -214,7 +232,10 @@ pub trait SqlDialect: self::private::TrustedBackend {
         doc = "implementation for `NoFromClause`"
     )]
     ///
-    /// See [`sql_dialect::from_clause_syntax`] for provided default implementations
+    #[cfg_attr(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+        doc = "See [`sql_dialect::from_clause_syntax`] for provided default implementations"
+    )]
     type EmptyFromClauseSyntax;
     /// Configures how this backend handles `EXISTS()` expressions.
     ///
@@ -228,7 +249,10 @@ pub trait SqlDialect: self::private::TrustedBackend {
         doc = "implementation for `Exists`"
     )]
     ///
-    /// See [`sql_dialect::exists_syntax`] for provided default implementations
+    #[cfg_attr(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+        doc = "See [`sql_dialect::exists_syntax`] for provided default implementations"
+    )]
     type ExistsSyntax;
 
     /// Configures how this backend handles `IN()` and `NOT IN()` expressions.
@@ -245,18 +269,43 @@ pub trait SqlDialect: self::private::TrustedBackend {
         doc = "implementations for `In`, `NotIn` and `Many`"
     )]
     ///
-    /// See `[sql_dialect::array_comparison`] for provided default implementations
-    type ArrayComparision;
+    #[cfg_attr(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+        doc = "See [`sql_dialect::array_comparison`] for provided default implementations"
+    )]
+    type ArrayComparison;
 }
 
 /// This module contains all options provided by diesel to configure the [`SqlDialect`] trait.
-pub mod sql_dialect {
+// This module is only public behind the unstable feature flag, as we may want to change SqlDialect
+// implementations of existing backends because of:
+// * The backend gained support for previously unsupported SQL operations
+// * The backend fixed/introduced a bug that requires special handling
+// * We got some edge case wrong with sharing the implementation between backends
+//
+// By not exposing these types publically we are able to change the exact definitions later on
+// as users cannot write trait bounds that ensure that a specific type is used in place of
+// an existing associated type.
+#[diesel_derives::__diesel_public_if(
+    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+)]
+pub(crate) mod sql_dialect {
+    #![cfg_attr(
+        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
+        // Otherwise there are false positives
+        // because the lint seems to believe that these pub statements
+        // are not required, but they are required through the various backend impls
+        allow(unreachable_pub)
+    )]
     #[cfg(doc)]
     use super::SqlDialect;
 
     /// This module contains all diesel provided reusable options to
     /// configure [`SqlDialect::OnConflictClause`]
-    pub mod on_conflict_clause {
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    pub(crate) mod on_conflict_clause {
         /// A marker trait indicating if a `ON CONFLICT` clause is supported or not
         ///
         /// If you use a custom type to specify specialized support for `ON CONFLICT` clauses
@@ -271,7 +320,10 @@ pub mod sql_dialect {
 
     /// This module contains all reusable options to configure
     /// [`SqlDialect::ReturningClause`]
-    pub mod returning_clause {
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    pub(crate) mod returning_clause {
         /// A marker trait indicating if a `RETURNING` clause is supported or not
         ///
         /// If you use custom type to specify specialized support for `RETURNING` clauses
@@ -292,7 +344,10 @@ pub mod sql_dialect {
 
     /// This module contains all reusable options to configure
     /// [`SqlDialect::InsertWithDefaultKeyword`]
-    pub mod default_keyword_for_insert {
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    pub(crate) mod default_keyword_for_insert {
         /// A marker trait indicating if a `DEFAULT` like expression
         /// is supported as part of `INSERT INTO` clauses to indicate
         /// that a default value should be inserted at a specific position
@@ -318,7 +373,10 @@ pub mod sql_dialect {
 
     /// This module contains all reusable options to configure
     /// [`SqlDialect::BatchInsertSupport`]
-    pub mod batch_insert_support {
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    pub(crate) mod batch_insert_support {
         /// A marker trait indicating if batch insert statements
         /// are supported for this backend or not
         pub trait SupportsBatchInsert {}
@@ -341,7 +399,10 @@ pub mod sql_dialect {
 
     /// This module contains all reusable options to configure
     /// [`SqlDialect::DefaultValueClauseForInsert`]
-    pub mod default_value_clause {
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    pub(crate) mod default_value_clause {
 
         /// Indicates that this backend uses the
         /// `DEFAULT VALUES` syntax to specify
@@ -353,7 +414,10 @@ pub mod sql_dialect {
 
     /// This module contains all reusable options to configure
     /// [`SqlDialect::EmptyFromClauseSyntax`]
-    pub mod from_clause_syntax {
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    pub(crate) mod from_clause_syntax {
 
         /// Indicates that this backend skips
         /// the `FROM` clause in `SELECT` statements
@@ -364,7 +428,10 @@ pub mod sql_dialect {
 
     /// This module contains all reusable options to configure
     /// [`SqlDialect::ExistsSyntax`]
-    pub mod exists_syntax {
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    pub(crate) mod exists_syntax {
 
         /// Indicates that this backend
         /// treats `EXIST()` as function
@@ -374,8 +441,11 @@ pub mod sql_dialect {
     }
 
     /// This module contains all reusable options to configure
-    /// [`SqlDialect::ArrayComparision`]
-    pub mod array_comparision {
+    /// [`SqlDialect::ArrayComparison`]
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    pub(crate) mod array_comparison {
 
         /// Indicates that this backend requires a single bind
         /// per array element in `IN()` and `NOT IN()` expression
diff --git a/diesel/src/connection/commit_error_processor.rs b/diesel/src/connection/commit_error_processor.rs
deleted file mode 100644
index 25845ca8f555..000000000000
--- a/diesel/src/connection/commit_error_processor.rs
+++ /dev/null
@@ -1,162 +0,0 @@
-//! A module to evaluate what to do when a commit triggers an error.
-use crate::result::Error;
-
-/// Transaction status returned upon error on commit.
-#[derive(Debug)]
-#[non_exhaustive]
-#[cfg_attr(
-    doc_cfg,
-    doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
-)]
-pub enum CommitErrorOutcome {
-    /// Necessitates a rollback to return to a valid transaction
-    RollbackAndThrow(Error),
-    /// Broken transaction. Returned if an error has occurred earlier in a Postgres transaction.
-    Throw(Error),
-    /// Broken transaction. Similar to `Throw`, but marks the manager as broken. It should switch
-    /// to `TransactionManagerStatus::InError` and refuse to run additional operations.
-    ThrowAndMarkManagerAsBroken(Error),
-}
-
-/// Trait needed for the transaction manager.
-#[cfg_attr(
-    doc_cfg,
-    doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
-)]
-pub trait CommitErrorProcessor {
-    /// Returns the status of the transaction following an error upon commit.
-    /// When any of these kinds of error happen on `COMMIT`, it is expected
-    /// that a `ROLLBACK` would succeed, leaving the transaction in a non-broken state.
-    /// If there are other such errors, it is fine to add them here.
-    fn process_commit_error(&self, error: Error) -> CommitErrorOutcome;
-}
-
-/// Default implementation of CommitErrorProcessor::process_commit_error(), used for MySql and
-/// Sqlite connections. Returns `CommitErrorOutcome::RollbackAndThrow` if the transaction depth is
-/// greater than 1, the error is a `DatabaseError` and the error kind is either
-/// `DatabaseErrorKind::SerializationFailure` or `DatabaseErrorKind::ReadOnlyTransaction`
-#[cfg_attr(
-    doc_cfg,
-    doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
-)]
-#[cfg(any(
-    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
-    feature = "mysql",
-    feature = "sqlite"
-))]
-#[diesel_derives::__diesel_public_if(
-    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
-)]
-pub(crate) fn default_process_commit_error(
-    transaction_state: &super::ValidTransactionManagerStatus,
-    error: Error,
-) -> CommitErrorOutcome {
-    use crate::result::DatabaseErrorKind;
-
-    if let Some(transaction_depth) = transaction_state.transaction_depth() {
-        match error {
-            // Neither mysql nor sqlite do currently produce these errors
-            // we keep this match arm here for the case we may generate
-            // such errors in future versions of diesel
-            Error::DatabaseError(DatabaseErrorKind::ReadOnlyTransaction, _)
-            | Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _)
-                if transaction_depth.get() == 1 =>
-            {
-                CommitErrorOutcome::RollbackAndThrow(error)
-            }
-            Error::AlreadyInTransaction
-            | Error::DatabaseError(DatabaseErrorKind::CheckViolation, _)
-            | Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
-            | Error::DatabaseError(DatabaseErrorKind::ForeignKeyViolation, _)
-            | Error::DatabaseError(DatabaseErrorKind::NotNullViolation, _)
-            | Error::DatabaseError(DatabaseErrorKind::ReadOnlyTransaction, _)
-            | Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _)
-            | Error::DatabaseError(DatabaseErrorKind::UnableToSendCommand, _)
-            | Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _)
-            | Error::DatabaseError(DatabaseErrorKind::Unknown, _)
-            | Error::DeserializationError(_)
-            | Error::InvalidCString(_)
-            | Error::NotFound
-            | Error::QueryBuilderError(_)
-            | Error::RollbackError(_)
-            | Error::RollbackTransaction
-            | Error::SerializationError(_)
-            | Error::NotInTransaction
-            | Error::BrokenTransaction
-            | Error::CommitTransactionFailed { .. } => CommitErrorOutcome::Throw(error),
-        }
-    } else {
-        unreachable!(
-            "Calling commit_error_processor outside of a transaction is implementation error.\
-            If you ever see this error message outside implementing a custom transaction manager\
-            please open a new issue at diesels issue tracker."
-        )
-    }
-}
-
-#[cfg(test)]
-#[cfg(any(
-    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
-    feature = "mysql",
-    feature = "sqlite"
-))]
-mod tests {
-    use super::CommitErrorOutcome;
-    use crate::connection::ValidTransactionManagerStatus;
-    use crate::result::{DatabaseErrorKind, Error};
-    use std::num::NonZeroU32;
-
-    #[test]
-    fn check_default_process_commit_error_implementation() {
-        let state = ValidTransactionManagerStatus {
-            // Transaction depth == 1, so one unnested transaction
-            transaction_depth: NonZeroU32::new(1),
-            previous_error_relevant_for_rollback: None,
-        };
-        let error = Error::DatabaseError(
-            DatabaseErrorKind::ReadOnlyTransaction,
-            Box::new(String::from("whatever")),
-        );
-        let action = super::default_process_commit_error(&state, error);
-        assert!(matches!(action, CommitErrorOutcome::RollbackAndThrow(_)));
-
-        let error = Error::DatabaseError(
-            DatabaseErrorKind::UnableToSendCommand,
-            Box::new(String::from("whatever")),
-        );
-        let action = super::default_process_commit_error(&state, error);
-        assert!(matches!(action, CommitErrorOutcome::Throw(_)));
-
-        let state = ValidTransactionManagerStatus {
-            // Transaction depth == 2, so two nested transactions
-            transaction_depth: NonZeroU32::new(2),
-            previous_error_relevant_for_rollback: None,
-        };
-        let error = Error::DatabaseError(
-            DatabaseErrorKind::ReadOnlyTransaction,
-            Box::new(String::from("whatever")),
-        );
-        let action = super::default_process_commit_error(&state, error);
-        assert!(matches!(action, CommitErrorOutcome::Throw(_)));
-    }
-
-    #[test]
-    #[should_panic]
-    fn check_invalid_transaction_state_rejected() {
-        let state = ValidTransactionManagerStatus {
-            // Transaction depth == None, so no transaction running, so nothing
-            // to rollback. Something went wrong so mark everything as broken.
-            transaction_depth: None,
-            previous_error_relevant_for_rollback: None,
-        };
-        let error = Error::DatabaseError(
-            DatabaseErrorKind::ReadOnlyTransaction,
-            Box::new(String::from("whatever")),
-        );
-        let action = super::default_process_commit_error(&state, error);
-        assert!(matches!(
-            action,
-            CommitErrorOutcome::ThrowAndMarkManagerAsBroken(_)
-        ));
-    }
-}
diff --git a/diesel/src/connection/mod.rs b/diesel/src/connection/mod.rs
index b1d82951f30d..defeb5c2ac2d 100644
--- a/diesel/src/connection/mod.rs
+++ b/diesel/src/connection/mod.rs
@@ -1,11 +1,5 @@
 //! Types related to database connections
 
-#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
-pub mod commit_error_processor;
-
-#[cfg(not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))]
-pub(crate) mod commit_error_processor;
-
 #[cfg(all(
     not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
     any(feature = "sqlite", feature = "postgres", feature = "mysql")
@@ -22,7 +16,7 @@ use crate::result::*;
 use std::fmt::Debug;
 
 pub use self::transaction_manager::{
-    AnsiTransactionManager, TransactionManager, TransactionManagerStatus,
+    AnsiTransactionManager, TransactionDepthChange, TransactionManager, TransactionManagerStatus,
     ValidTransactionManagerStatus,
 };
 
@@ -42,11 +36,11 @@ pub trait SimpleConnection {
     fn batch_execute(&mut self, query: &str) -> QueryResult<()>;
 }
 
-/// Return type of [`Connection::load`].
+/// Return type of [`LoadConnection::load`].
 ///
 /// Users should threat this type as `impl Iterator<Item = QueryResult<impl Row<DB>>>`
-pub type LoadRowIter<'conn, 'query, C, DB> =
-    <C as ConnectionGatWorkaround<'conn, 'query, DB>>::Cursor;
+pub type LoadRowIter<'conn, 'query, C, DB, B = DefaultLoadingMode> =
+    <C as ConnectionGatWorkaround<'conn, 'query, DB, B>>::Cursor;
 
 /// A connection to a database
 ///
@@ -72,10 +66,11 @@ pub type LoadRowIter<'conn, 'query, C, DB> =
 ///
 /// Wrapping an existing connection allows you to customize the implementation to
 /// add additional functionality, like for example instrumentation. For this use case
-/// you only need to implement `Connection` and all super traits. You should forward
-/// any method call to the wrapped connection type. It is **important** to also
-/// forward any method where diesel provides a default implementation, as the
-/// wrapped connection implementation may contain a customized implementation.
+/// you only need to implement `Connection`, [`LoadConnection`] and all super traits.
+/// You should forward any method call to the wrapped connection type.
+/// It is **important** to also forward any method where diesel provides a
+/// default implementation, as the wrapped connection implementation may
+/// contain a customized implementation.
 ///
 /// To allow the integration of your new connection type with other diesel features
 #[cfg_attr(
@@ -96,7 +91,7 @@ pub type LoadRowIter<'conn, 'query, C, DB> =
 /// based on a pure rust connection crate.
 ///
 /// **It's important to use prepared statements to implement the following methods:**
-/// * [`Connection::load`]
+/// * [`LoadConnection::load`]
 /// * [`Connection::execute_returning_count`]
 ///
 /// For performance reasons it may also be meaningful to cache already prepared statements.
@@ -196,7 +191,11 @@ pub type LoadRowIter<'conn, 'query, C, DB> =
 /// implementations to see how you can implement your own connection.
 pub trait Connection: SimpleConnection + Sized + Send
 where
-    Self: for<'a, 'b> ConnectionGatWorkaround<'a, 'b, <Self as Connection>::Backend>,
+    // This trait bound is there so that implementing a new connection is
+    // gated behind the `i-implement-a-third-party-backend-and-opt-into-breaking-changes`
+    // feature flag
+    for<'conn, 'query> Self:
+        ConnectionGatWorkaround<'conn, 'query, Self::Backend, DefaultLoadingMode>,
 {
     /// The backend this type connects to
     type Backend: Backend;
@@ -223,26 +222,22 @@ where
     /// For both cases the original result value will be returned from this function.
     ///
     /// If the transaction fails to commit due to a `SerializationFailure` or a
-    /// `ReadOnlyTransaction` a rollback will be attempted. In this case a
-    /// [`Error::CommitTransactionFailed`](crate::result::Error::CommitTransactionFailed)
-    /// error is returned, which contains details about the original error and
-    /// the success of the rollback attempt.
-    /// If the rollback failed the connection should be considered broken
+    /// `ReadOnlyTransaction` a rollback will be attempted.
+    /// If the rollback fails, the error will be returned in a
+    /// [`Error::RollbackErrorOnCommit`](crate::result::Error::RollbackErrorOnCommit),
+    /// from which you will be able to extract both the original commit error and
+    /// the rollback error.
+    /// In addition, the connection will be considered broken
     /// as it contains a uncommitted unabortable open transaction. Any further
     /// interaction with the transaction system will result in an returned error
-    /// in this cases.
+    /// in this case.
     ///
     /// If the closure returns an `Err(_)` and the rollback fails the function
-    /// will return a [`Error::RollbackError`](crate::result::Error::RollbackError)
-    /// wrapping the error generated by the rollback operation instead.
-    /// In this case the connection should be considered broken as it contains
-    /// an unabortable open transaction.
+    /// will return that rollback error directly, and the transaction manager will
+    /// be marked as broken as it contains a uncommitted unabortable open transaction.
     ///
     /// If a nested transaction fails to release the corresponding savepoint
-    /// a rollback will be attempted.  In this case a
-    /// [`Error::CommitTransactionFailed`](crate::result::Error::CommitTransactionFailed)
-    /// error is returned, which contains the original error and
-    /// details about the success of the rollback attempt.
+    /// the error will be returned directly.
     ///
     /// # Example
     ///
@@ -353,6 +348,35 @@ where
         user_result.expect("Transaction did not succeed")
     }
 
+    /// Execute a single SQL statements given by a query and return
+    /// number of affected rows
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
+    where
+        T: QueryFragment<Self::Backend> + QueryId;
+
+    /// Get access to the current transaction state of this connection
+    ///
+    /// This function should be used from [`TransactionManager`] to access
+    /// internally required state.
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    fn transaction_state(
+        &mut self,
+    ) -> &mut <Self::TransactionManager as TransactionManager<Self>>::TransactionStateData;
+}
+
+/// The specific part of a [`Connection`] which actually loads data from the database
+///
+/// This is a seperate trait to allow connection implementations to specify
+/// different loading modes via the generic paramater.
+pub trait LoadConnection<B = DefaultLoadingMode>: Connection
+where
+    for<'conn, 'query> Self: ConnectionGatWorkaround<'conn, 'query, Self::Backend, B>,
+{
     /// Executes a given query and returns any requested values
     ///
     /// This function executes a given query and returns the
@@ -370,30 +394,10 @@ where
     fn load<'conn, 'query, T>(
         &'conn mut self,
         source: T,
-    ) -> QueryResult<LoadRowIter<'conn, 'query, Self, Self::Backend>>
+    ) -> QueryResult<LoadRowIter<'conn, 'query, Self, Self::Backend, B>>
     where
         T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
         Self::Backend: QueryMetadata<T::SqlType>;
-
-    /// Execute a single SQL statements given by a query and return
-    /// number of affected rows
-    #[diesel_derives::__diesel_public_if(
-        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
-    )]
-    fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
-    where
-        T: QueryFragment<Self::Backend> + QueryId;
-
-    /// Get access to the current transaction state of this connection
-    ///
-    /// This function should be used from [`TransactionManager`] to access
-    /// internally required state.
-    #[diesel_derives::__diesel_public_if(
-        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
-    )]
-    fn transaction_state(
-        &mut self,
-    ) -> &mut <Self::TransactionManager as TransactionManager<Self>>::TransactionStateData;
 }
 
 /// A variant of the [`Connection`](trait.Connection.html) trait that is
@@ -428,6 +432,17 @@ where
     }
 }
 
+/// The default loading mode provided by a [`Connection`].
+///
+/// Checkout the documentation of concrete connection types for details about
+/// supported loading modes.
+///
+/// All types implementing [`Connection`] should provide at least
+/// a single [`LoadConnection<DefaultLoadingMode>`](self::LoadConnection)
+/// implementation.
+#[derive(Debug, Copy, Clone)]
+pub struct DefaultLoadingMode;
+
 impl<DB: Backend + 'static> dyn BoxableConnection<DB> {
     /// Downcast the current connection to a specific connection
     /// type.
@@ -472,6 +487,8 @@ mod private {
     use crate::backend::Backend;
     use crate::QueryResult;
 
+    use super::DefaultLoadingMode;
+
     /// This trait describes which cursor type is used by a given connection
     /// implementation. This trait is only useful in combination with [`Connection`].
     ///
@@ -482,12 +499,12 @@ mod private {
         doc_cfg,
         doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
     )]
-    pub trait ConnectionGatWorkaround<'conn, 'query, DB: Backend> {
-        /// The cursor type returned by [`Connection::load`]
+    pub trait ConnectionGatWorkaround<'conn, 'query, DB: Backend, B = DefaultLoadingMode> {
+        /// The cursor type returned by [`LoadConnection::load`]
         ///
         /// Users should handle this as opaque type that implements [`Iterator`]
         ///
-        /// [`Connection::load`]: super::Connection::load
+        /// [`LoadConnection::load`]: super::LoadConnection::load
         type Cursor: Iterator<Item = QueryResult<Self::Row>>;
         /// The row type used as [`Iterator::Item`] for the iterator implementation
         /// of [`ConnectionGatWorkaround::Cursor`]
diff --git a/diesel/src/connection/transaction_manager.rs b/diesel/src/connection/transaction_manager.rs
index e63f7db43374..1e5eb773fe89 100644
--- a/diesel/src/connection/transaction_manager.rs
+++ b/diesel/src/connection/transaction_manager.rs
@@ -1,6 +1,5 @@
-use crate::connection::commit_error_processor::{CommitErrorOutcome, CommitErrorProcessor};
 use crate::connection::Connection;
-use crate::result::{DatabaseErrorKind, Error, QueryResult};
+use crate::result::{Error, QueryResult};
 use std::borrow::Cow;
 use std::num::NonZeroU32;
 
@@ -56,10 +55,15 @@ pub trait TransactionManager<Conn: Connection> {
                 Self::commit_transaction(conn)?;
                 Ok(value)
             }
-            Err(e) => {
-                Self::rollback_transaction(conn).map_err(|e| Error::RollbackError(Box::new(e)))?;
-                Err(e)
-            }
+            Err(user_error) => match Self::rollback_transaction(conn) {
+                Ok(()) => Err(user_error),
+                Err(Error::BrokenTransactionManager) => {
+                    // In this case we are probably more interested by the
+                    // original error, which likely caused this
+                    Err(user_error)
+                }
+                Err(rollback_error) => Err(rollback_error.into()),
+            },
         }
     }
 }
@@ -89,18 +93,68 @@ impl Default for TransactionManagerStatus {
 
 impl TransactionManagerStatus {
     /// Returns the transaction depth if the transaction manager's status is valid, or returns
-    /// [`Error::BrokenTransaction`] if the transaction manager is in error.
+    /// [`Error::BrokenTransactionManager`] if the transaction manager is in error.
     pub fn transaction_depth(&self) -> QueryResult<Option<NonZeroU32>> {
         match self {
             TransactionManagerStatus::Valid(valid_status) => Ok(valid_status.transaction_depth()),
-            TransactionManagerStatus::InError => Err(Error::BrokenTransaction),
+            TransactionManagerStatus::InError => Err(Error::BrokenTransactionManager),
+        }
+    }
+
+    #[cfg(any(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+        feature = "postgres",
+    ))]
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    /// Whether we may be interested in calling
+    /// `set_top_level_transaction_requires_rollback_if_not_broken`
+    ///
+    /// You should typically not need this outside of a custom backend implementation
+    pub(crate) fn is_not_broken_and_in_transaction(&self) -> bool {
+        match self {
+            TransactionManagerStatus::Valid(valid_status) => valid_status.in_transaction.is_some(),
+            TransactionManagerStatus::InError => false,
+        }
+    }
+
+    #[cfg(any(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+        feature = "postgres",
+        feature = "mysql",
+        test
+    ))]
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    /// If in transaction and transaction manager is not broken, registers that the
+    /// connection can not be used anymore until top-level transaction is rolled back
+    pub(crate) fn set_top_level_transaction_requires_rollback(&mut self) {
+        if let TransactionManagerStatus::Valid(ValidTransactionManagerStatus {
+            in_transaction:
+                Some(InTransactionStatus {
+                    top_level_transaction_requires_rollback,
+                    ..
+                }),
+        }) = self
+        {
+            *top_level_transaction_requires_rollback = true;
         }
     }
 
+    /// Sets the transaction manager status to InError
+    ///
+    /// Subsequent attempts to use transaction-related features will result in a
+    /// [`Error::BrokenTransactionManager`] error
+    pub fn set_in_error(&mut self) {
+        *self = TransactionManagerStatus::InError
+    }
+
     fn transaction_state(&mut self) -> QueryResult<&mut ValidTransactionManagerStatus> {
         match self {
             TransactionManagerStatus::Valid(valid_status) => Ok(valid_status),
-            TransactionManagerStatus::InError => Err(Error::BrokenTransaction),
+            TransactionManagerStatus::InError => Err(Error::BrokenTransactionManager),
         }
     }
 }
@@ -109,8 +163,14 @@ impl TransactionManagerStatus {
 #[allow(missing_copy_implementations)]
 #[derive(Debug, Default)]
 pub struct ValidTransactionManagerStatus {
-    pub(super) transaction_depth: Option<NonZeroU32>,
-    pub(crate) previous_error_relevant_for_rollback: Option<(DatabaseErrorKind, String)>,
+    in_transaction: Option<InTransactionStatus>,
+}
+
+#[allow(missing_copy_implementations)]
+#[derive(Debug)]
+struct InTransactionStatus {
+    transaction_depth: NonZeroU32,
+    top_level_transaction_requires_rollback: bool,
 }
 
 impl ValidTransactionManagerStatus {
@@ -119,7 +179,7 @@ impl ValidTransactionManagerStatus {
     /// This value is `None` if no current transaction is running
     /// otherwise the number of nested transactions is returned.
     pub fn transaction_depth(&self) -> Option<NonZeroU32> {
-        self.transaction_depth
+        self.in_transaction.as_ref().map(|it| it.transaction_depth)
     }
 
     /// Update the transaction depth by adding the value of the `transaction_depth_change` parameter if the `query` is
@@ -127,30 +187,38 @@ impl ValidTransactionManagerStatus {
     pub fn change_transaction_depth(
         &mut self,
         transaction_depth_change: TransactionDepthChange,
-        query: QueryResult<()>,
     ) -> QueryResult<()> {
-        if query.is_ok() {
-            match (&mut self.transaction_depth, transaction_depth_change) {
-                (Some(depth), TransactionDepthChange::IncreaseDepth) => {
-                    // This is always `Some(_)`
-                    self.transaction_depth = NonZeroU32::new(depth.get().saturating_add(1));
-                }
-                (Some(depth), TransactionDepthChange::DecreaseDepth) => {
-                    // This sets `transaction_depth` to `None` as soon as we reach zero
-                    self.transaction_depth = NonZeroU32::new(depth.get().saturating_sub(1));
-                }
-                (None, TransactionDepthChange::IncreaseDepth) => {
-                    self.transaction_depth = NonZeroU32::new(1);
-                }
-                (None, TransactionDepthChange::DecreaseDepth) => {
-                    // We screwed up something somewhere
-                    // we cannot decrease the transaction count if
-                    // we are not inside a transaction
-                    return Err(Error::NotInTransaction);
+        match (&mut self.in_transaction, transaction_depth_change) {
+            (Some(in_transaction), TransactionDepthChange::IncreaseDepth) => {
+                // Can be replaced with saturating_add directly on NonZeroU32 once
+                // <https://github.com/rust-lang/rust/issues/84186> is stable
+                in_transaction.transaction_depth =
+                    NonZeroU32::new(in_transaction.transaction_depth.get().saturating_add(1))
+                        .expect("nz + nz is always non-zero");
+                Ok(())
+            }
+            (Some(in_transaction), TransactionDepthChange::DecreaseDepth) => {
+                // This sets `transaction_depth` to `None` as soon as we reach zero
+                match NonZeroU32::new(in_transaction.transaction_depth.get() - 1) {
+                    Some(depth) => in_transaction.transaction_depth = depth,
+                    None => self.in_transaction = None,
                 }
+                Ok(())
+            }
+            (None, TransactionDepthChange::IncreaseDepth) => {
+                self.in_transaction = Some(InTransactionStatus {
+                    transaction_depth: NonZeroU32::new(1).expect("1 is non-zero"),
+                    top_level_transaction_requires_rollback: false,
+                });
+                Ok(())
+            }
+            (None, TransactionDepthChange::DecreaseDepth) => {
+                // We screwed up something somewhere
+                // we cannot decrease the transaction count if
+                // we are not inside a transaction
+                Err(Error::NotInTransaction)
             }
         }
-        query
     }
 }
 
@@ -168,7 +236,7 @@ impl AnsiTransactionManager {
         conn: &mut Conn,
     ) -> QueryResult<&mut ValidTransactionManagerStatus>
     where
-        Conn: Connection<TransactionManager = Self> + CommitErrorProcessor,
+        Conn: Connection<TransactionManager = Self>,
     {
         conn.transaction_state().status.transaction_state()
     }
@@ -180,14 +248,15 @@ impl AnsiTransactionManager {
     /// Returns an error if already inside of a transaction.
     pub fn begin_transaction_sql<Conn>(conn: &mut Conn, sql: &str) -> QueryResult<()>
     where
-        Conn: Connection<TransactionManager = Self> + CommitErrorProcessor,
+        Conn: Connection<TransactionManager = Self>,
     {
         let state = Self::get_transaction_state(conn)?;
         match state.transaction_depth() {
             None => {
-                let res = conn.batch_execute(sql);
-                let state = Self::get_transaction_state(conn)?;
-                state.change_transaction_depth(TransactionDepthChange::IncreaseDepth, res)
+                conn.batch_execute(sql)?;
+                Self::get_transaction_state(conn)?
+                    .change_transaction_depth(TransactionDepthChange::IncreaseDepth)?;
+                Ok(())
             }
             Some(_depth) => Err(Error::AlreadyInTransaction),
         }
@@ -196,7 +265,7 @@ impl AnsiTransactionManager {
 
 impl<Conn> TransactionManager<Conn> for AnsiTransactionManager
 where
-    Conn: Connection<TransactionManager = Self> + CommitErrorProcessor,
+    Conn: Connection<TransactionManager = Self>,
 {
     type TransactionStateData = Self;
 
@@ -208,168 +277,141 @@ where
                 Cow::from(format!("SAVEPOINT diesel_savepoint_{}", transaction_depth))
             }
         };
-        let result = conn.batch_execute(&*start_transaction_sql);
-        let state = Self::get_transaction_state(conn)?;
-        state.change_transaction_depth(TransactionDepthChange::IncreaseDepth, result)
+        conn.batch_execute(&*start_transaction_sql)?;
+        Self::get_transaction_state(conn)?
+            .change_transaction_depth(TransactionDepthChange::IncreaseDepth)?;
+
+        Ok(())
     }
 
     fn rollback_transaction(conn: &mut Conn) -> QueryResult<()> {
         let transaction_state = Self::get_transaction_state(conn)?;
-        let rollback_sql = match transaction_state.transaction_depth() {
+
+        let rollback_sql = match transaction_state.in_transaction {
+            Some(ref mut in_transaction) => {
+                match in_transaction.transaction_depth.get() {
+                    1 => Cow::Borrowed("ROLLBACK"),
+                    depth_gt1 => {
+                        if in_transaction.top_level_transaction_requires_rollback {
+                            // There's no point in *actually* rolling back this one
+                            // because we won't be able to do anything until top-level
+                            // is rolled back.
+
+                            // To make it easier on the user (that they don't have to really look
+                            // at actual transaction depth and can just rely on the number of
+                            // times they have called begin/commit/rollback) we don't mark the
+                            // transaction manager as out of the savepoints as soon as we
+                            // realize there is that issue, but instead we still decrement here:
+                            in_transaction.transaction_depth = NonZeroU32::new(depth_gt1 - 1)
+                                .expect("Depth was checked to be > 1");
+                            return Ok(());
+                        } else {
+                            Cow::Owned(format!(
+                                "ROLLBACK TO SAVEPOINT diesel_savepoint_{}",
+                                depth_gt1 - 1
+                            ))
+                        }
+                    }
+                }
+            }
             None => return Err(Error::NotInTransaction),
-            Some(transaction_depth) if transaction_depth.get() == 1 => Cow::from("ROLLBACK"),
-            Some(transaction_depth) => Cow::from(format!(
-                "ROLLBACK TO SAVEPOINT diesel_savepoint_{}",
-                transaction_depth.get() - 1
-            )),
         };
 
-        if let Some((kind, msg)) = transaction_state
-            .previous_error_relevant_for_rollback
-            .take()
-        {
-            // we can safely ignore the result of process_commit_error here
-            // as the only other error than the "rollback error" variants
-            // is failing to load the transaction state, but that's something
-            // we have already done above
-            let _ = process_commit_error(
-                conn,
-                crate::result::Error::DatabaseError(kind, Box::new(String::new())),
-                rollback_sql,
-            );
-            let transaction_state = Self::get_transaction_state(conn)?;
-            if transaction_state
-                .transaction_depth
-                .map(|t| t.get())
-                .unwrap_or_default()
-                > 0
-            {
-                transaction_state.previous_error_relevant_for_rollback = Some((kind, msg.clone()));
+        match conn.batch_execute(&*rollback_sql) {
+            Ok(()) => {
+                Self::get_transaction_state(conn)?
+                    .change_transaction_depth(TransactionDepthChange::DecreaseDepth)?;
+                Ok(())
+            }
+            Err(rollback_error) => {
+                let tm_status = Self::transaction_manager_status_mut(conn);
+                match tm_status {
+                    TransactionManagerStatus::Valid(ValidTransactionManagerStatus {
+                        in_transaction:
+                            Some(InTransactionStatus {
+                                transaction_depth,
+                                top_level_transaction_requires_rollback,
+                            }),
+                    }) if transaction_depth.get() > 1
+                        && !*top_level_transaction_requires_rollback =>
+                    {
+                        // A savepoint failed to rollback - we may still attempt to repair
+                        // the connection by rolling back top-level transaction.
+                        *transaction_depth = NonZeroU32::new(transaction_depth.get() - 1)
+                            .expect("Depth was checked to be > 1");
+                        *top_level_transaction_requires_rollback = true;
+                    }
+                    _ => tm_status.set_in_error(),
+                }
+                Err(rollback_error)
             }
-            return Err(crate::result::Error::DatabaseError(kind, Box::new(msg)));
         }
-        let result = conn.batch_execute(&*rollback_sql);
-        let state = Self::get_transaction_state(conn)?;
-        state.change_transaction_depth(TransactionDepthChange::DecreaseDepth, result)
     }
 
     /// If the transaction fails to commit due to a `SerializationFailure` or a
     /// `ReadOnlyTransaction` a rollback will be attempted. If the rollback succeeds,
     /// the original error will be returned, otherwise the error generated by the rollback
-    /// will be returned. In the second case the connection should be considered broken
+    /// will be returned. In the second case the connection will be considered broken
     /// as it contains a uncommitted unabortable open transaction.
     fn commit_transaction(conn: &mut Conn) -> QueryResult<()> {
         let transaction_state = Self::get_transaction_state(conn)?;
         let transaction_depth = transaction_state.transaction_depth();
-        let (commit_sql, rollback_sql) = match transaction_depth {
+        let commit_sql = match transaction_depth {
             None => return Err(Error::NotInTransaction),
-            Some(transaction_depth) if transaction_depth.get() == 1 => {
-                (Cow::from("COMMIT"), Cow::from("ROLLBACK"))
-            }
-            Some(transaction_depth) => (
-                Cow::from(format!(
-                    "RELEASE SAVEPOINT diesel_savepoint_{}",
-                    transaction_depth.get() - 1
-                )),
-                Cow::from(format!(
-                    "ROLLBACK TO SAVEPOINT diesel_savepoint_{}",
-                    transaction_depth.get() - 1
-                )),
-            ),
+            Some(transaction_depth) if transaction_depth.get() == 1 => Cow::Borrowed("COMMIT"),
+            Some(transaction_depth) => Cow::Owned(format!(
+                "RELEASE SAVEPOINT diesel_savepoint_{}",
+                transaction_depth.get() - 1
+            )),
         };
-        let res = conn.batch_execute(&*commit_sql);
-        let state = Self::get_transaction_state(conn)?;
-        match res {
+        match conn.batch_execute(&*commit_sql) {
             Ok(()) => {
-                // commit succeeded, so we just decrease the transaction depth
-                // and we are done
-                state.change_transaction_depth(TransactionDepthChange::DecreaseDepth, res)
-            }
-            Err(error) => process_commit_error(conn, error, rollback_sql),
-        }
-    }
-
-    fn transaction_manager_status_mut(conn: &mut Conn) -> &mut TransactionManagerStatus {
-        &mut conn.transaction_state().status
-    }
-
-    fn transaction<F, R, E>(conn: &mut Conn, f: F) -> Result<R, E>
-    where
-        F: FnOnce(&mut Conn) -> Result<R, E>,
-        E: From<Error>,
-    {
-        Self::begin_transaction(conn)?;
-        match f(&mut *conn) {
-            Ok(value) => {
-                Self::commit_transaction(conn)?;
-                Ok(value)
+                Self::get_transaction_state(conn)?
+                    .change_transaction_depth(TransactionDepthChange::DecreaseDepth)?;
+                Ok(())
             }
-            Err(e) => {
-                let transaction_state = Self::get_transaction_state(conn)?;
-                let is_error_relevant_for_rollback = transaction_state
-                    .previous_error_relevant_for_rollback
-                    .is_some();
-
-                Self::rollback_transaction(conn).map_err(|e| {
-                    if is_error_relevant_for_rollback {
-                        if let Error::DatabaseError(
-                            crate::result::DatabaseErrorKind::SerializationFailure,
-                            _,
-                        ) = e
-                        {
-                            return e;
+            Err(commit_error) => {
+                if let TransactionManagerStatus::Valid(ValidTransactionManagerStatus {
+                    in_transaction:
+                        Some(InTransactionStatus {
+                            ref mut transaction_depth,
+                            top_level_transaction_requires_rollback: true,
+                        }),
+                }) = conn.transaction_state().status
+                {
+                    match transaction_depth.get() {
+                        1 => match Self::rollback_transaction(conn) {
+                            Ok(()) => {}
+                            Err(rollback_error) => {
+                                conn.transaction_state().status.set_in_error();
+                                return Err(Error::RollbackErrorOnCommit {
+                                    rollback_error: Box::new(rollback_error),
+                                    commit_error: Box::new(commit_error),
+                                });
+                            }
+                        },
+                        depth_gt1 => {
+                            // There's no point in *actually* rolling back this one
+                            // because we won't be able to do anything until top-level
+                            // is rolled back.
+
+                            // To make it easier on the user (that they don't have to really look
+                            // at actual transaction depth and can just rely on the number of
+                            // times they have called begin/commit/rollback) we don't mark the
+                            // transaction manager as out of the savepoints as soon as we
+                            // realize there is that issue, but instead we still decrement here:
+                            *transaction_depth = NonZeroU32::new(depth_gt1 - 1)
+                                .expect("Depth was checked to be > 1");
                         }
                     }
-
-                    Error::RollbackError(Box::new(e))
-                })?;
-                Err(e)
+                }
+                Err(commit_error)
             }
         }
     }
-}
 
-fn process_commit_error<Conn>(
-    conn: &mut Conn,
-    error: Error,
-    rollback_sql: Cow<'_, str>,
-) -> QueryResult<()>
-where
-    Conn: Connection<TransactionManager = AnsiTransactionManager> + CommitErrorProcessor,
-{
-    let commit_error_outcome = conn.process_commit_error(error);
-    let state = AnsiTransactionManager::get_transaction_state(conn)?;
-    match commit_error_outcome {
-        CommitErrorOutcome::RollbackAndThrow(error) => {
-            // We should try to rollback the transaction here
-            let rollback_result = conn.batch_execute(&*rollback_sql);
-            let state = AnsiTransactionManager::get_transaction_state(conn)?;
-            let rollback_result = state
-                .change_transaction_depth(TransactionDepthChange::DecreaseDepth, rollback_result);
-            Err(Error::CommitTransactionFailed {
-                commit_error: Box::new(error),
-                rollback_result: Box::new(rollback_result),
-            })
-        }
-        CommitErrorOutcome::Throw(error) => {
-            // The error processor indicated that we just
-            // need to decrease the transaction depth and return the original error
-            let _ = state.change_transaction_depth(TransactionDepthChange::DecreaseDepth, Ok(()));
-            Err(Error::CommitTransactionFailed {
-                commit_error: Box::new(error),
-                rollback_result: Box::new(Ok(())),
-            })
-        }
-        CommitErrorOutcome::ThrowAndMarkManagerAsBroken(error) => {
-            // The connection contains an unrecoverable broken transaction
-            // so mark the transaction state as broken and return the error
-            *AnsiTransactionManager::transaction_manager_status_mut(conn) =
-                TransactionManagerStatus::InError;
-            Err(Error::CommitTransactionFailed {
-                commit_error: Box::new(error),
-                rollback_result: Box::new(Err(Error::BrokenTransaction)),
-            })
-        }
+    fn transaction_manager_status_mut(conn: &mut Conn) -> &mut TransactionManagerStatus {
+        &mut conn.transaction_state().status
     }
 }
 
@@ -377,28 +419,33 @@ where
 mod test {
     // Mock connection.
     mod mock {
-        use crate::connection::commit_error_processor::{CommitErrorOutcome, CommitErrorProcessor};
         use crate::connection::transaction_manager::AnsiTransactionManager;
         use crate::connection::{
             Connection, ConnectionGatWorkaround, SimpleConnection, TransactionManager,
         };
-        use crate::expression::QueryMetadata;
-        use crate::query_builder::{AsQuery, QueryFragment, QueryId};
-        use crate::result::{Error, QueryResult};
+        use crate::result::QueryResult;
         use crate::test_helpers::TestConnection;
+        use std::collections::VecDeque;
 
         pub(crate) struct MockConnection {
-            pub(crate) next_result: Option<QueryResult<usize>>,
-            pub(crate) next_batch_execute_result: Option<QueryResult<()>>,
-            pub(crate) broken: bool,
+            pub(crate) next_results: VecDeque<QueryResult<usize>>,
+            pub(crate) next_batch_execute_results: VecDeque<QueryResult<()>>,
+            pub(crate) top_level_requires_rollback_after_next_batch_execute: bool,
             transaction_state: AnsiTransactionManager,
         }
 
         impl SimpleConnection for MockConnection {
             fn batch_execute(&mut self, _query: &str) -> QueryResult<()> {
-                self.next_batch_execute_result
-                    .take()
-                    .expect("No next result")
+                let res = self
+                    .next_batch_execute_results
+                    .pop_front()
+                    .expect("No next result");
+                if self.top_level_requires_rollback_after_next_batch_execute {
+                    self.transaction_state
+                        .status
+                        .set_top_level_transaction_requires_rollback();
+                }
+                res
             }
         }
 
@@ -419,16 +466,6 @@ mod test {
             >>::Row;
         }
 
-        impl CommitErrorProcessor for MockConnection {
-            fn process_commit_error(&self, error: Error) -> CommitErrorOutcome {
-                if self.broken {
-                    CommitErrorOutcome::ThrowAndMarkManagerAsBroken(error)
-                } else {
-                    CommitErrorOutcome::Throw(error)
-                }
-            }
-        }
-
         impl Connection for MockConnection {
             type Backend = <TestConnection as Connection>::Backend;
 
@@ -436,31 +473,19 @@ mod test {
 
             fn establish(_database_url: &str) -> crate::ConnectionResult<Self> {
                 Ok(Self {
-                    next_result: None,
-                    next_batch_execute_result: None,
-                    broken: false,
+                    next_results: VecDeque::new(),
+                    next_batch_execute_results: VecDeque::new(),
+                    top_level_requires_rollback_after_next_batch_execute: false,
                     transaction_state: AnsiTransactionManager::default(),
                 })
             }
 
-            fn load<'conn, 'query, T>(
-                &'conn mut self,
-                _source: T,
-            ) -> QueryResult<<Self as ConnectionGatWorkaround<'conn, 'query, Self::Backend>>::Cursor>
-            where
-                T: AsQuery,
-                T::Query: QueryFragment<Self::Backend> + QueryId + 'query,
-                Self::Backend: QueryMetadata<T::SqlType>,
-            {
-                unimplemented!()
-            }
-
             fn execute_returning_count<T>(&mut self, _source: &T) -> QueryResult<usize>
             where
                 T: crate::query_builder::QueryFragment<Self::Backend>
                     + crate::query_builder::QueryId,
             {
-                self.next_result.take().expect("No next result")
+                self.next_results.pop_front().expect("No next result")
             }
 
             fn transaction_state(
@@ -521,31 +546,47 @@ mod test {
         let mut conn = mock::MockConnection::establish("mock").expect("Mock connection");
 
         // Set result for BEGIN
-        conn.next_batch_execute_result = Some(Ok(()));
+        conn.next_batch_execute_results.push_back(Ok(()));
         let result = conn.transaction(|conn| {
-            conn.next_result = Some(Ok(1));
+            conn.next_results.push_back(Ok(1));
             let query_result = sql_query("SELECT 1").execute(conn);
             assert!(query_result.is_ok());
-            conn.broken = true;
             // Set result for COMMIT attempt
-            conn.next_batch_execute_result = Some(Err(Error::DatabaseError(
-                DatabaseErrorKind::Unknown,
-                Box::new("whatever".to_string()),
-            )));
+            conn.next_batch_execute_results
+                .push_back(Err(Error::DatabaseError(
+                    DatabaseErrorKind::Unknown,
+                    Box::new("commit fails".to_string()),
+                )));
+            conn.top_level_requires_rollback_after_next_batch_execute = true;
+            conn.next_batch_execute_results
+                .push_back(Err(Error::DatabaseError(
+                    DatabaseErrorKind::Unknown,
+                    Box::new("rollback also fails".to_string()),
+                )));
             Ok(())
         });
+        assert!(
+            matches!(
+                &result,
+                Err(Error::RollbackErrorOnCommit {
+                    rollback_error,
+                    commit_error
+                }) if matches!(**commit_error, Error::DatabaseError(DatabaseErrorKind::Unknown, _))
+                    && matches!(&**rollback_error,
+                        Error::DatabaseError(DatabaseErrorKind::Unknown, msg)
+                            if msg.message() == "rollback also fails"
+                    )
+            ),
+            "Got {:?}",
+            result
+        );
         assert!(matches!(
-            result,
-            Err(Error::CommitTransactionFailed{commit_error, ..}) if matches!(&*commit_error, Error::DatabaseError(DatabaseErrorKind::Unknown, _))
+            *AnsiTransactionManager::transaction_manager_status_mut(&mut conn),
+            TransactionManagerStatus::InError
         ));
-        assert!(matches!(
-            *<AnsiTransactionManager as TransactionManager<mock::MockConnection>>::transaction_manager_status_mut(
-                &mut conn),
-            TransactionManagerStatus::InError)
-        );
         // Ensure the transaction manager is unusable
         let result = conn.transaction(|_conn| Ok(()));
-        assert!(matches!(result, Err(Error::BrokenTransaction)))
+        assert!(matches!(result, Err(Error::BrokenTransactionManager)))
     }
 
     #[test]
@@ -672,6 +713,9 @@ mod test {
 
     #[test]
     #[cfg(feature = "mysql")]
+    // This function uses a collect with side effects (spawning threads)
+    // so clippy is wrong here
+    #[allow(clippy::needless_collect)]
     fn mysql_transaction_depth_commits_tracked_properly_on_serialization_failure() {
         use crate::result::DatabaseErrorKind::SerializationFailure;
         use crate::result::Error::DatabaseError;
@@ -775,6 +819,9 @@ mod test {
 
     #[test]
     #[cfg(feature = "mysql")]
+    // This function uses a collect with side effects (spawning threads)
+    // so clippy is wrong here
+    #[allow(clippy::needless_collect)]
     fn mysql_nested_transaction_depth_commits_tracked_properly_on_serialization_failure() {
         use crate::result::DatabaseErrorKind::SerializationFailure;
         use crate::result::Error::DatabaseError;
@@ -834,7 +881,7 @@ mod test {
                     let result =
                     conn.transaction(|conn| {
                         assert_eq!(NonZeroU32::new(1), <AnsiTransactionManager as TransactionManager<MysqlConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
-                        conn.transaction(|conn| {
+                       conn.transaction(|conn| {
                             assert_eq!(NonZeroU32::new(2), <AnsiTransactionManager as TransactionManager<MysqlConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
                             let _ = serialization_example::table
                                 .filter(serialization_example::class.eq(i))
diff --git a/diesel/src/expression/array_comparison.rs b/diesel/src/expression/array_comparison.rs
index 9b10a48994e1..9b914d96c9cd 100644
--- a/diesel/src/expression/array_comparison.rs
+++ b/diesel/src/expression/array_comparison.rs
@@ -23,7 +23,7 @@ use std::marker::PhantomData;
 ///
 /// Third party backend can customize the [`QueryFragment`]
 /// implementation of this query dsl node via
-/// [`SqlDialect::ArrayComparision`]. A customized implementation
+/// [`SqlDialect::ArrayComparison`]. A customized implementation
 /// is expected to provide the same sematics as a ANSI SQL
 /// `IN` expression.
 ///
@@ -43,7 +43,7 @@ pub struct In<T, U> {
 ///
 /// Third party backend can customize the [`QueryFragment`]
 /// implementation of this query dsl node via
-/// [`SqlDialect::ArrayComparision`]. A customized implementation
+/// [`SqlDialect::ArrayComparison`]. A customized implementation
 /// is expected to provide the same sematics as a ANSI SQL
 /// `NOT IN` expression.0
 ///
@@ -89,18 +89,17 @@ where
 impl<T, U, DB> QueryFragment<DB> for In<T, U>
 where
     DB: Backend,
-    Self: QueryFragment<DB, DB::ArrayComparision>,
+    Self: QueryFragment<DB, DB::ArrayComparison>,
 {
     fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
-        <Self as QueryFragment<DB, DB::ArrayComparision>>::walk_ast(self, pass)
+        <Self as QueryFragment<DB, DB::ArrayComparison>>::walk_ast(self, pass)
     }
 }
 
-impl<T, U, DB> QueryFragment<DB, sql_dialect::array_comparision::AnsiSqlArrayComparison>
-    for In<T, U>
+impl<T, U, DB> QueryFragment<DB, sql_dialect::array_comparison::AnsiSqlArrayComparison> for In<T, U>
 where
     DB: Backend
-        + SqlDialect<ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison>,
+        + SqlDialect<ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison>,
     T: QueryFragment<DB>,
     U: QueryFragment<DB> + MaybeEmpty,
 {
@@ -120,18 +119,18 @@ where
 impl<T, U, DB> QueryFragment<DB> for NotIn<T, U>
 where
     DB: Backend,
-    Self: QueryFragment<DB, DB::ArrayComparision>,
+    Self: QueryFragment<DB, DB::ArrayComparison>,
 {
     fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
-        <Self as QueryFragment<DB, DB::ArrayComparision>>::walk_ast(self, pass)
+        <Self as QueryFragment<DB, DB::ArrayComparison>>::walk_ast(self, pass)
     }
 }
 
-impl<T, U, DB> QueryFragment<DB, sql_dialect::array_comparision::AnsiSqlArrayComparison>
+impl<T, U, DB> QueryFragment<DB, sql_dialect::array_comparison::AnsiSqlArrayComparison>
     for NotIn<T, U>
 where
     DB: Backend
-        + SqlDialect<ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison>,
+        + SqlDialect<ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison>,
     T: QueryFragment<DB>,
     U: QueryFragment<DB> + MaybeEmpty,
 {
@@ -234,7 +233,7 @@ where
 ///
 /// Third party backend can customize the [`QueryFragment`]
 /// implementation of this query dsl node via
-/// [`SqlDialect::ArrayComparision`]. The default
+/// [`SqlDialect::ArrayComparison`]. The default
 /// implementation does generate one bind per value
 /// in the `values` field.
 ///
@@ -290,20 +289,20 @@ where
 
 impl<ST, I, DB> QueryFragment<DB> for Many<ST, I>
 where
-    Self: QueryFragment<DB, DB::ArrayComparision>,
+    Self: QueryFragment<DB, DB::ArrayComparison>,
     DB: Backend,
 {
     fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
-        <Self as QueryFragment<DB, DB::ArrayComparision>>::walk_ast(self, pass)
+        <Self as QueryFragment<DB, DB::ArrayComparison>>::walk_ast(self, pass)
     }
 }
 
-impl<ST, I, DB> QueryFragment<DB, sql_dialect::array_comparision::AnsiSqlArrayComparison>
+impl<ST, I, DB> QueryFragment<DB, sql_dialect::array_comparison::AnsiSqlArrayComparison>
     for Many<ST, I>
 where
     DB: Backend
         + HasSqlType<ST>
-        + SqlDialect<ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison>,
+        + SqlDialect<ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison>,
     ST: SingleValue,
     I: ToSql<ST, DB>,
 {
diff --git a/diesel/src/expression/mod.rs b/diesel/src/expression/mod.rs
index b2c026631be6..0f6fefc6f953 100644
--- a/diesel/src/expression/mod.rs
+++ b/diesel/src/expression/mod.rs
@@ -212,9 +212,9 @@ where
     T: Expression<SqlType = ST>,
     ST: SqlType + TypedExpressionType,
 {
-    type Expression = Self;
+    type Expression = T;
 
-    fn as_expression(self) -> Self {
+    fn as_expression(self) -> T {
         self
     }
 }
diff --git a/diesel/src/expression/nullable.rs b/diesel/src/expression/nullable.rs
index 223c636e5538..8912b002a6e9 100644
--- a/diesel/src/expression/nullable.rs
+++ b/diesel/src/expression/nullable.rs
@@ -48,19 +48,6 @@ impl<T: QueryId> QueryId for Nullable<T> {
     const HAS_STATIC_QUERY_ID: bool = T::HAS_STATIC_QUERY_ID;
 }
 
-impl<T, DB> Selectable<DB> for Option<T>
-where
-    DB: Backend,
-    T: Selectable<DB>,
-    Nullable<T::SelectExpression>: Expression,
-{
-    type SelectExpression = Nullable<T::SelectExpression>;
-
-    fn construct_selection() -> Self::SelectExpression {
-        Nullable::new(T::construct_selection())
-    }
-}
-
 impl<T, QS> SelectableExpression<QS> for Nullable<T>
 where
     Self: AppearsOnTable<QS>,
diff --git a/diesel/src/lib.rs b/diesel/src/lib.rs
index fc55327e96d5..fd4a1a784e90 100644
--- a/diesel/src/lib.rs
+++ b/diesel/src/lib.rs
@@ -130,8 +130,8 @@
 //! - `i-implement-a-third-party-backend-and-opt-into-breaking-changes`: This feature opens up some otherwise
 //! private API, that can be useful to implement a third party [`Backend`](crate::backend::Backend)
 //! or write a custom [`Connection`](crate::connection::Connection) implementation. **Do not use this feature for
-//! any other usecase**. By enabling this feature you explicitly opt out diesel stability gurantees. We explicitly
-//! reserve us the right to break API's exported under this feature flag in any upcomming minor version release.
+//! any other usecase**. By enabling this feature you explicitly opt out diesel stability guarantees. We explicitly
+//! reserve us the right to break API's exported under this feature flag in any upcoming minor version release.
 //! If you publish a crate depending on this feature flag consider to restrict the supported diesel version to the
 //! currently released minor version.
 //! - `serde_json`: This feature flag enables support for (de)serializing json values from the database using
@@ -140,17 +140,19 @@
 //! types provided by `chrono`
 //! - `uuid`: This feature flag enables support for (de)serializing uuid values from the database using types
 //! provided by `uuid`
-//! - `network-address`: This feature flag enables support for (de)serializing IP and Macadresse values from the
-//! database using types provided by `ipnetwork`
-//! - `numeric`: This feature flag enables support for (de)support numeric values from the database using types
+//! - `network-address`: This feature flag enables support for (de)serializing
+//! IP values from the database using types provided by `ipnetwork`.
+//! - `ipnet-address`: This feature flag enables support for (de)serializing IP
+//! values from the database using types provided by `ipnet`.
+//! - `numeric`: This feature flag enables support for (de)serializing numeric values from the database using types
 //! provided by `bigdecimal`
 //! - `r2d2`: This feature flag enables support for the `r2d2` connection pool implementation.
 //! - `extras`: This feature enables the feature flaged support for any third party crate. This implies the
 //! following feature flags: `serde_json`, `chrono`, `uuid`, `network-address`, `numeric`, `r2d2`
 //! - `with-deprecated`: This feature enables items marked as `#[deprecated]`. It is enabled by default.
-//! disabling this feature explicitly opts out diesels stability gurantee.
+//! disabling this feature explicitly opts out diesels stability guarantee.
 //! - `without-deprecated`: This feature disables any item marked as `#[deprecated]`. Enabling this feature
-//! explicitly opts out the stability gurantee given by diesel. This feature overrides the `with-deprecated`.
+//! explicitly opts out the stability guarantee given by diesel. This feature overrides the `with-deprecated`.
 //! Note that this may also remove items that are not shown as `#[deprecated]` in our documentation, due to
 //! various bugs in rustdoc. It can be used to check if you depend on any such hidden `#[deprecated]` item.
 //!
@@ -178,7 +180,6 @@
     clippy::redundant_field_names,
     clippy::type_complexity
 )]
-#![cfg_attr(test, allow(clippy::option_map_unwrap_or, clippy::result_unwrap_used))]
 #![warn(
     clippy::unwrap_used,
     clippy::print_stdout,
@@ -191,6 +192,7 @@
     clippy::items_after_statements,
     clippy::used_underscore_binding
 )]
+#![cfg_attr(test, allow(clippy::map_unwrap_or, clippy::unwrap_used))]
 
 extern crate diesel_derives;
 
@@ -280,6 +282,7 @@ pub mod helper_types {
     use super::query_dsl::methods::*;
     use super::query_dsl::*;
     use super::query_source::{aliasing, joins};
+    use crate::connection::DefaultLoadingMode;
     use crate::query_builder::select_clause::SelectClause;
 
     #[doc(inline)]
@@ -454,8 +457,8 @@ pub mod helper_types {
     /// [`Iterator`](std::iter::Iterator) of [`QueryResult<U>`](crate::result::QueryResult)
     ///
     /// See [`RunQueryDsl::load_iter`] for more information
-    pub type LoadIter<'conn, 'query, Q, Conn, U> =
-        <Q as load_dsl::LoadQueryGatWorkaround<'conn, 'query, Conn, U>>::Ret;
+    pub type LoadIter<'conn, 'query, Q, Conn, U, B = DefaultLoadingMode> =
+        <Q as load_dsl::LoadQueryGatWorkaround<'conn, 'query, Conn, U, B>>::Ret;
 
     /// Maps `F` to `Alias<S>`
     ///
diff --git a/diesel/src/macros/mod.rs b/diesel/src/macros/mod.rs
index a5c80b97359b..910b21f3eca9 100644
--- a/diesel/src/macros/mod.rs
+++ b/diesel/src/macros/mod.rs
@@ -63,9 +63,9 @@ macro_rules! __diesel_internal_backend_specific_table_impls {
             type FromClause = $crate::query_builder::Only<S>;
             type OnClause = <$crate::query_builder::Only<S> as $crate::JoinTo<$table>>::OnClause;
 
-            fn join_target(rhs: $crate::query_builder::Only<S>) -> (Self::FromClause, Self::OnClause) {
-                let (_, on_clause) = $crate::query_builder::Only::<S>::join_target($table);
-                (rhs, on_clause)
+            fn join_target(__diesel_internal_rhs: $crate::query_builder::Only<S>) -> (Self::FromClause, Self::OnClause) {
+                let (_, __diesel_internal_on_clause) = $crate::query_builder::Only::<S>::join_target($table);
+                (__diesel_internal_rhs, __diesel_internal_on_clause)
             }
         }
 
@@ -113,13 +113,15 @@ macro_rules! __diesel_column {
             $crate::internal::table_macro::StaticQueryFragmentInstance<table>: $crate::query_builder::QueryFragment<DB>,
         {
             #[allow(non_snake_case)]
-            fn walk_ast<'b>(&'b self, mut __out: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()>
+            fn walk_ast<'b>(&'b self, mut __diesel_internal_out: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()>
             {
-                const FROM_CLAUSE: $crate::internal::table_macro::StaticQueryFragmentInstance<table> = $crate::internal::table_macro::StaticQueryFragmentInstance::new();
+                if !__diesel_internal_out.should_skip_from() {
+                    const FROM_CLAUSE: $crate::internal::table_macro::StaticQueryFragmentInstance<table> = $crate::internal::table_macro::StaticQueryFragmentInstance::new();
 
-                FROM_CLAUSE.walk_ast(__out.reborrow())?;
-                __out.push_sql(".");
-                __out.push_identifier($sql_name)
+                    FROM_CLAUSE.walk_ast(__diesel_internal_out.reborrow())?;
+                    __diesel_internal_out.push_sql(".");
+                }
+                __diesel_internal_out.push_identifier($sql_name)
             }
         }
 
@@ -195,9 +197,9 @@ macro_rules! __diesel_column {
         {
             type Output = $crate::dsl::Eq<Self, T::Expression>;
 
-            fn eq_all(self, rhs: T) -> Self::Output {
+            fn eq_all(self, __diesel_internal_rhs: T) -> Self::Output {
                 use $crate::expression_methods::ExpressionMethods;
-                self.eq(rhs)
+                self.eq(__diesel_internal_rhs)
             }
         }
 
@@ -805,8 +807,8 @@ macro_rules! __diesel_table_impl {
                 DB: $crate::backend::Backend,
                 <table as $crate::internal::table_macro::StaticQueryFragment>::Component: $crate::query_builder::QueryFragment<DB>
             {
-                fn walk_ast<'b>(&'b self, pass: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()> {
-                    <table as $crate::internal::table_macro::StaticQueryFragment>::STATIC_COMPONENT.walk_ast(pass)
+                fn walk_ast<'b>(&'b self, __diesel_internal_pass: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()> {
+                    <table as $crate::internal::table_macro::StaticQueryFragment>::STATIC_COMPONENT.walk_ast(__diesel_internal_pass)
                 }
             }
 
@@ -887,8 +889,8 @@ macro_rules! __diesel_table_impl {
             {
                 type Out = $crate::query_source::AliasedField<S, C>;
 
-                fn map(column: C, alias: &$crate::query_source::Alias<S>) -> Self::Out {
-                    alias.field(column)
+                fn map(__diesel_internal_column: C, __diesel_internal_alias: &$crate::query_source::Alias<S>) -> Self::Out {
+                    __diesel_internal_alias.field(__diesel_internal_column)
                 }
             }
 
@@ -904,9 +906,9 @@ macro_rules! __diesel_table_impl {
                 type FromClause = $crate::internal::table_macro::Join<Left, Right, Kind>;
                 type OnClause = <$crate::internal::table_macro::Join<Left, Right, Kind> as $crate::JoinTo<table>>::OnClause;
 
-                fn join_target(rhs: $crate::internal::table_macro::Join<Left, Right, Kind>) -> (Self::FromClause, Self::OnClause) {
-                    let (_, on_clause) = $crate::internal::table_macro::Join::join_target(table);
-                    (rhs, on_clause)
+                fn join_target(__diesel_internal_rhs: $crate::internal::table_macro::Join<Left, Right, Kind>) -> (Self::FromClause, Self::OnClause) {
+                    let (_, __diesel_internal_on_clause) = $crate::internal::table_macro::Join::join_target(table);
+                    (__diesel_internal_rhs, __diesel_internal_on_clause)
                 }
             }
 
@@ -916,9 +918,9 @@ macro_rules! __diesel_table_impl {
                 type FromClause = $crate::internal::table_macro::JoinOn<Join, On>;
                 type OnClause = <$crate::internal::table_macro::JoinOn<Join, On> as $crate::JoinTo<table>>::OnClause;
 
-                fn join_target(rhs: $crate::internal::table_macro::JoinOn<Join, On>) -> (Self::FromClause, Self::OnClause) {
-                    let (_, on_clause) = $crate::internal::table_macro::JoinOn::join_target(table);
-                    (rhs, on_clause)
+                fn join_target(__diesel_internal_rhs: $crate::internal::table_macro::JoinOn<Join, On>) -> (Self::FromClause, Self::OnClause) {
+                    let (_, __diesel_internal_on_clause) = $crate::internal::table_macro::JoinOn::join_target(table);
+                    (__diesel_internal_rhs, __diesel_internal_on_clause)
                 }
             }
 
@@ -929,9 +931,9 @@ macro_rules! __diesel_table_impl {
                 type FromClause = $crate::internal::table_macro::SelectStatement<$crate::internal::table_macro::FromClause<F>, S, D, W, O, L, Of, G>;
                 type OnClause = <$crate::internal::table_macro::SelectStatement<$crate::internal::table_macro::FromClause<F>, S, D, W, O, L, Of, G> as $crate::JoinTo<table>>::OnClause;
 
-                fn join_target(rhs: $crate::internal::table_macro::SelectStatement<$crate::internal::table_macro::FromClause<F>, S, D, W, O, L, Of, G>) -> (Self::FromClause, Self::OnClause) {
-                    let (_, on_clause) = $crate::internal::table_macro::SelectStatement::join_target(table);
-                    (rhs, on_clause)
+                fn join_target(__diesel_internal_rhs: $crate::internal::table_macro::SelectStatement<$crate::internal::table_macro::FromClause<F>, S, D, W, O, L, Of, G>) -> (Self::FromClause, Self::OnClause) {
+                    let (_, __diesel_internal_on_clause) = $crate::internal::table_macro::SelectStatement::join_target(table);
+                    (__diesel_internal_rhs, __diesel_internal_on_clause)
                 }
             }
 
@@ -941,9 +943,9 @@ macro_rules! __diesel_table_impl {
             {
                 type FromClause = $crate::internal::table_macro::BoxedSelectStatement<'a, $crate::internal::table_macro::FromClause<QS>, ST, DB>;
                 type OnClause = <$crate::internal::table_macro::BoxedSelectStatement<'a, $crate::internal::table_macro::FromClause<QS>, ST, DB> as $crate::JoinTo<table>>::OnClause;
-                fn join_target(rhs: $crate::internal::table_macro::BoxedSelectStatement<'a, $crate::internal::table_macro::FromClause<QS>, ST, DB>) -> (Self::FromClause, Self::OnClause) {
-                    let (_, on_clause) = $crate::internal::table_macro::BoxedSelectStatement::join_target(table);
-                    (rhs, on_clause)
+                fn join_target(__diesel_internal_rhs: $crate::internal::table_macro::BoxedSelectStatement<'a, $crate::internal::table_macro::FromClause<QS>, ST, DB>) -> (Self::FromClause, Self::OnClause) {
+                    let (_, __diesel_internal_on_clause) = $crate::internal::table_macro::BoxedSelectStatement::join_target(table);
+                    (__diesel_internal_rhs, __diesel_internal_on_clause)
                 }
             }
 
@@ -954,9 +956,9 @@ macro_rules! __diesel_table_impl {
                 type FromClause = $crate::query_source::Alias<S>;
                 type OnClause = <$crate::query_source::Alias<S> as $crate::JoinTo<table>>::OnClause;
 
-                fn join_target(rhs: $crate::query_source::Alias<S>) -> (Self::FromClause, Self::OnClause) {
-                    let (_, on_clause) = $crate::query_source::Alias::<S>::join_target(table);
-                    (rhs, on_clause)
+                fn join_target(__diesel_internal_rhs: $crate::query_source::Alias<S>) -> (Self::FromClause, Self::OnClause) {
+                    let (_, __diesel_internal_on_clause) = $crate::query_source::Alias::<S>::join_target(table);
+                    (__diesel_internal_rhs, __diesel_internal_on_clause)
                 }
             }
 
@@ -1015,13 +1017,17 @@ macro_rules! __diesel_table_impl {
                     <table as $crate::QuerySource>::FromClause: $crate::query_builder::QueryFragment<DB>,
                 {
                     #[allow(non_snake_case)]
-                    fn walk_ast<'b>(&'b self, mut __out: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()>
+                    fn walk_ast<'b>(&'b self, mut __diesel_internal_out: $crate::query_builder::AstPass<'_, 'b, DB>) -> $crate::result::QueryResult<()>
                     {
                         use $crate::QuerySource;
-                        const FROM_CLAUSE: $crate::internal::table_macro::StaticQueryFragmentInstance<table> = $crate::internal::table_macro::StaticQueryFragmentInstance::new();
 
-                        FROM_CLAUSE.walk_ast(__out.reborrow())?;
-                        __out.push_sql(".*");
+                        if !__diesel_internal_out.should_skip_from() {
+                            const FROM_CLAUSE: $crate::internal::table_macro::StaticQueryFragmentInstance<table> = $crate::internal::table_macro::StaticQueryFragmentInstance::new();
+
+                            FROM_CLAUSE.walk_ast(__diesel_internal_out.reborrow())?;
+                            __diesel_internal_out.push_sql(".");
+                        }
+                        __diesel_internal_out.push_sql("*");
                         Ok(())
                     }
                 }
@@ -1129,9 +1135,10 @@ macro_rules! __diesel_table_generate_static_query_fragment_for_table {
 ///
 /// The generated `ON` clause will always join to the primary key of the parent
 /// table. This macro removes the need to call [`.on`] explicitly, you will
-/// still need to invoke [`allow_tables_to_appear_in_same_query!`] for these two tables to
-/// be able to use the resulting query, unless you are using `diesel print-schema`
-/// which will generate it for you.
+/// still need to invoke
+/// [`allow_tables_to_appear_in_same_query!`](crate::allow_tables_to_appear_in_same_query)
+/// for these two tables to be able to use the resulting query, unless you are
+/// using `diesel print-schema` which will generate it for you.
 ///
 /// If you are using `diesel print-schema`, an invocation of this macro
 /// will be generated for every foreign key in your database unless
diff --git a/diesel/src/macros/ops.rs b/diesel/src/macros/ops.rs
index 6f460644c736..626627ec2b84 100644
--- a/diesel/src/macros/ops.rs
+++ b/diesel/src/macros/ops.rs
@@ -14,8 +14,8 @@ macro_rules! operator_allowed {
         {
             type Output = $crate::internal::table_macro::ops::$op<Self, Rhs::Expression>;
 
-            fn $fn_name(self, rhs: Rhs) -> Self::Output {
-                $crate::internal::table_macro::ops::$op::new(self, rhs.as_expression())
+            fn $fn_name(self, __diesel_internal_rhs: Rhs) -> Self::Output {
+                $crate::internal::table_macro::ops::$op::new(self, __diesel_internal_rhs.as_expression())
             }
         }
     };
diff --git a/diesel/src/mysql/backend.rs b/diesel/src/mysql/backend.rs
index 7645cc6c2354..e04537e4efe8 100644
--- a/diesel/src/mysql/backend.rs
+++ b/diesel/src/mysql/backend.rs
@@ -89,7 +89,7 @@ impl SqlDialect for Mysql {
     type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax;
     type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax;
 
-    type ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison;
+    type ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison;
 }
 
 impl DieselReserveSpecialization for Mysql {}
diff --git a/diesel/src/mysql/connection/bind.rs b/diesel/src/mysql/connection/bind.rs
index 2ca4c2d141e8..7ae8bd54dddd 100644
--- a/diesel/src/mysql/connection/bind.rs
+++ b/diesel/src/mysql/connection/bind.rs
@@ -846,8 +846,9 @@ mod tests {
             ).execute(conn)
             .unwrap();
 
-        let stmt = conn.prepared_query(&crate::sql_query(
-            "SELECT
+        let stmt = crate::mysql::connection::prepared_query(
+            &crate::sql_query(
+                "SELECT
                     tiny_int, small_int, medium_int, int_col,
                     big_int, unsigned_int, zero_fill_int,
                     numeric_col, decimal_col, float_col, double_col, bit_col,
@@ -857,7 +858,10 @@ mod tests {
                     ST_AsText(polygon_col), ST_AsText(multipoint_col), ST_AsText(multilinestring_col),
                     ST_AsText(multipolygon_col), ST_AsText(geometry_collection), json_col
                  FROM all_mysql_types",
-        )).unwrap();
+            ),
+            &mut conn.statement_cache,
+            &mut conn.raw_connection,
+        ).unwrap();
 
         let metadata = stmt.metadata().unwrap();
         let mut output_binds =
@@ -1289,8 +1293,6 @@ mod tests {
 
     #[test]
     fn check_json_bind() {
-        let conn = &mut crate::test_helpers::connection();
-
         table! {
             json_test {
                 id -> Integer,
@@ -1298,6 +1300,8 @@ mod tests {
             }
         }
 
+        let conn = &mut crate::test_helpers::connection();
+
         crate::sql_query("DROP TABLE IF EXISTS json_test CASCADE")
             .execute(conn)
             .unwrap();
diff --git a/diesel/src/mysql/connection/mod.rs b/diesel/src/mysql/connection/mod.rs
index 7e5bc4746690..93f510d95632 100644
--- a/diesel/src/mysql/connection/mod.rs
+++ b/diesel/src/mysql/connection/mod.rs
@@ -8,9 +8,6 @@ use self::stmt::iterator::StatementIterator;
 use self::stmt::Statement;
 use self::url::ConnectionOptions;
 use super::backend::Mysql;
-use crate::connection::commit_error_processor::{
-    default_process_commit_error, CommitErrorOutcome, CommitErrorProcessor,
-};
 use crate::connection::statement_cache::{MaybeCached, StatementCache};
 use crate::connection::*;
 use crate::expression::QueryMetadata;
@@ -23,6 +20,81 @@ use crate::RunQueryDsl;
 #[allow(missing_debug_implementations, missing_copy_implementations)]
 /// A connection to a MySQL database. Connection URLs should be in the form
 /// `mysql://[user[:password]@]host/database_name`
+///
+/// # Supported loading model implementations
+///
+/// * [`DefaultLoadingMode`]
+///
+/// As `MysqlConnection` only supports a single loading mode implementation
+/// it is **not required** to explicitly specify a loading mode
+/// when calling [`RunQueryDsl::load_iter()`] or [`LoadConnection::load`]
+///
+/// ## DefaultLoadingMode
+///
+/// `MysqlConnection` only supports a single loading mode, which loads
+/// values row by row from the result set.
+///
+/// ```rust
+/// # include!("../../doctest_setup.rs");
+/// #
+/// # fn main() {
+/// #     run_test().unwrap();
+/// # }
+/// #
+/// # fn run_test() -> QueryResult<()> {
+/// #     use schema::users;
+/// #     let connection = &mut establish_connection();
+/// use diesel::connection::DefaultLoadingMode;
+/// { // scope to restrict the lifetime of the iterator
+///     let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
+///
+///     for r in iter1 {
+///         let (id, name) = r?;
+///         println!("Id: {} Name: {}", id, name);
+///     }
+/// }
+///
+/// // works without specifying the loading mode
+/// let iter2 = users::table.load_iter::<(i32, String), _>(connection)?;
+///
+/// for r in iter2 {
+///     let (id, name) = r?;
+///     println!("Id: {} Name: {}", id, name);
+/// }
+/// #   Ok(())
+/// # }
+/// ```
+///
+/// This mode does **not support** creating
+/// multiple iterators using the same connection.
+///
+/// ```compile_fail
+/// # include!("../../doctest_setup.rs");
+/// #
+/// # fn main() {
+/// #     run_test().unwrap();
+/// # }
+/// #
+/// # fn run_test() -> QueryResult<()> {
+/// #     use schema::users;
+/// #     let connection = &mut establish_connection();
+/// use diesel::connection::DefaultLoadingMode;
+///
+/// let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
+/// let iter2 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
+///
+/// for r in iter1 {
+///     let (id, name) = r?;
+///     println!("Id: {} Name: {}", id, name);
+/// }
+///
+/// for r in iter2 {
+///     let (id, name) = r?;
+///     println!("Id: {} Name: {}", id, name);
+/// }
+/// #   Ok(())
+/// # }
+/// ```
 pub struct MysqlConnection {
     raw_connection: RawConnection,
     transaction_state: AnsiTransactionManager,
@@ -43,18 +115,6 @@ impl<'conn, 'query> ConnectionGatWorkaround<'conn, 'query, Mysql> for MysqlConne
     type Row = self::stmt::iterator::MysqlRow;
 }
 
-impl CommitErrorProcessor for MysqlConnection {
-    fn process_commit_error(&self, error: Error) -> CommitErrorOutcome {
-        let state = match self.transaction_state.status {
-            TransactionManagerStatus::InError => {
-                return CommitErrorOutcome::Throw(Error::BrokenTransaction)
-            }
-            TransactionManagerStatus::Valid(ref v) => v,
-        };
-        default_process_commit_error(state, error)
-    }
-}
-
 impl Connection for MysqlConnection {
     type Backend = Mysql;
     type TransactionManager = AnsiTransactionManager;
@@ -83,60 +143,61 @@ impl Connection for MysqlConnection {
         Ok(conn)
     }
 
-    fn load<'conn, 'query, T>(
-        &'conn mut self,
-        source: T,
-    ) -> QueryResult<LoadRowIter<'conn, 'query, Self, Self::Backend>>
-    where
-        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
-        Self::Backend: QueryMetadata<T::SqlType>,
-    {
-        let stmt = self.prepared_query(&source)?;
-
-        let mut metadata = Vec::new();
-        Mysql::row_metadata(&mut (), &mut metadata);
-
-        StatementIterator::from_stmt(stmt, &metadata)
-    }
-
-    #[doc(hidden)]
     fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
     where
         T: QueryFragment<Self::Backend> + QueryId,
     {
-        let err = {
-            let stmt = self.prepared_query(source)?;
-            let res = unsafe { stmt.execute() };
-            match res {
-                Ok(stmt_use) => return Ok(stmt_use.affected_rows()),
-                Err(e) => e,
-            }
-        };
-        if let Error::DatabaseError(DatabaseErrorKind::SerializationFailure, msg) = err {
-            if let AnsiTransactionManager {
-                status: TransactionManagerStatus::Valid(ref mut valid),
-            } = self.transaction_state
-            {
-                valid.previous_error_relevant_for_rollback = Some((
-                    DatabaseErrorKind::SerializationFailure,
-                    msg.message().to_owned(),
-                ))
-            }
-            Err(Error::DatabaseError(
-                DatabaseErrorKind::SerializationFailure,
-                msg,
-            ))
-        } else {
-            Err(err)
-        }
+        update_transaction_manager_status(
+            prepared_query(&source, &mut self.statement_cache, &mut self.raw_connection).and_then(
+                |stmt| {
+                    let stmt_use = unsafe { stmt.execute() }?;
+                    Ok(stmt_use.affected_rows())
+                },
+            ),
+            &mut self.transaction_state,
+        )
     }
 
-    #[doc(hidden)]
     fn transaction_state(&mut self) -> &mut AnsiTransactionManager {
         &mut self.transaction_state
     }
 }
 
+#[inline(always)]
+fn update_transaction_manager_status<T>(
+    query_result: QueryResult<T>,
+    transaction_manager: &mut AnsiTransactionManager,
+) -> QueryResult<T> {
+    if let Err(Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _)) = query_result {
+        transaction_manager
+            .status
+            .set_top_level_transaction_requires_rollback()
+    }
+    query_result
+}
+
+impl LoadConnection<DefaultLoadingMode> for MysqlConnection {
+    fn load<'conn, 'query, T>(
+        &'conn mut self,
+        source: T,
+    ) -> QueryResult<LoadRowIter<'conn, 'query, Self, Self::Backend>>
+    where
+        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
+        Self::Backend: QueryMetadata<T::SqlType>,
+    {
+        update_transaction_manager_status(
+            prepared_query(&source, &mut self.statement_cache, &mut self.raw_connection).and_then(
+                |stmt| {
+                    let mut metadata = Vec::new();
+                    Mysql::row_metadata(&mut (), &mut metadata);
+                    StatementIterator::from_stmt(stmt, &metadata)
+                },
+            ),
+            &mut self.transaction_state,
+        )
+    }
+}
+
 #[cfg(feature = "r2d2")]
 impl crate::r2d2::R2D2Connection for MysqlConnection {
     fn ping(&mut self) -> QueryResult<()> {
@@ -144,33 +205,36 @@ impl crate::r2d2::R2D2Connection for MysqlConnection {
     }
 
     fn is_broken(&mut self) -> bool {
-        self.transaction_state
-            .status
-            .transaction_depth()
-            .map(|d| d.is_none())
-            .unwrap_or(true)
+        match self.transaction_state.status.transaction_depth() {
+            // all transactions are closed
+            // so we don't consider this connection broken
+            Ok(None) => false,
+            // The transaction manager is in an error state
+            // or contains an open transaction
+            // Therefore we consider this connection broken
+            Err(_) | Ok(Some(_)) => true,
+        }
     }
 }
 
-impl MysqlConnection {
-    fn prepared_query<'a, T: QueryFragment<Mysql> + QueryId>(
-        &'a mut self,
-        source: &'_ T,
-    ) -> QueryResult<MaybeCached<'a, Statement>> {
-        let cache = &mut self.statement_cache;
-        let conn = &mut self.raw_connection;
-
-        let mut stmt = cache.cached_statement(source, &Mysql, &[], |sql, _| conn.prepare(sql))?;
-        let mut bind_collector = RawBytesBindCollector::new();
-        source.collect_binds(&mut bind_collector, &mut (), &Mysql)?;
-        let binds = bind_collector
-            .metadata
-            .into_iter()
-            .zip(bind_collector.binds);
-        stmt.bind(binds)?;
-        Ok(stmt)
-    }
+fn prepared_query<'a, T: QueryFragment<Mysql> + QueryId>(
+    source: &'_ T,
+    statement_cache: &'a mut StatementCache<Mysql, Statement>,
+    raw_connection: &'a mut RawConnection,
+) -> QueryResult<MaybeCached<'a, Statement>> {
+    let mut stmt = statement_cache
+        .cached_statement(source, &Mysql, &[], |sql, _| raw_connection.prepare(sql))?;
+    let mut bind_collector = RawBytesBindCollector::new();
+    source.collect_binds(&mut bind_collector, &mut (), &Mysql)?;
+    let binds = bind_collector
+        .metadata
+        .into_iter()
+        .zip(bind_collector.binds);
+    stmt.bind(binds)?;
+    Ok(stmt)
+}
 
+impl MysqlConnection {
     fn set_config_options(&mut self) -> QueryResult<()> {
         crate::sql_query("SET sql_mode=(SELECT CONCAT(@@sql_mode, ',PIPES_AS_CONCAT'))")
             .execute(self)?;
diff --git a/diesel/src/mysql/connection/raw.rs b/diesel/src/mysql/connection/raw.rs
index 697414840358..ba50ac40b9cc 100644
--- a/diesel/src/mysql/connection/raw.rs
+++ b/diesel/src/mysql/connection/raw.rs
@@ -59,18 +59,12 @@ impl RawConnection {
             // Make sure you don't use the fake one!
             ffi::mysql_real_connect(
                 self.0.as_ptr(),
-                host.map(CStr::as_ptr).unwrap_or_else(|| ptr::null_mut()),
+                host.map(CStr::as_ptr).unwrap_or_else(ptr::null),
                 user.as_ptr(),
-                password
-                    .map(CStr::as_ptr)
-                    .unwrap_or_else(|| ptr::null_mut()),
-                database
-                    .map(CStr::as_ptr)
-                    .unwrap_or_else(|| ptr::null_mut()),
+                password.map(CStr::as_ptr).unwrap_or_else(ptr::null),
+                database.map(CStr::as_ptr).unwrap_or_else(ptr::null),
                 u32::from(port.unwrap_or(0)),
-                unix_socket
-                    .map(CStr::as_ptr)
-                    .unwrap_or_else(|| ptr::null_mut()),
+                unix_socket.map(CStr::as_ptr).unwrap_or_else(ptr::null),
                 client_flags.bits().into(),
             )
         };
diff --git a/diesel/src/mysql/connection/stmt/iterator.rs b/diesel/src/mysql/connection/stmt/iterator.rs
index 63f7feef39fc..cb307d3d8b97 100644
--- a/diesel/src/mysql/connection/stmt/iterator.rs
+++ b/diesel/src/mysql/connection/stmt/iterator.rs
@@ -234,6 +234,7 @@ fn fun_with_row_iters() {
         }
     }
 
+    use crate::connection::LoadConnection;
     use crate::deserialize::{FromSql, FromSqlRow};
     use crate::prelude::*;
     use crate::row::{Field, Row};
diff --git a/diesel/src/mysql/query_builder/mod.rs b/diesel/src/mysql/query_builder/mod.rs
index 37d73cc9275e..75d54c674ee5 100644
--- a/diesel/src/mysql/query_builder/mod.rs
+++ b/diesel/src/mysql/query_builder/mod.rs
@@ -26,7 +26,7 @@ impl QueryBuilder<Mysql> for MysqlQueryBuilder {
 
     fn push_identifier(&mut self, identifier: &str) -> QueryResult<()> {
         self.push_sql("`");
-        self.push_sql(&identifier.replace("`", "``"));
+        self.push_sql(&identifier.replace('`', "``"));
         self.push_sql("`");
         Ok(())
     }
diff --git a/diesel/src/mysql/value.rs b/diesel/src/mysql/value.rs
index 8053c2c99634..cc0d4cf5335e 100644
--- a/diesel/src/mysql/value.rs
+++ b/diesel/src/mysql/value.rs
@@ -4,7 +4,7 @@ use crate::deserialize;
 use std::error::Error;
 
 /// Raw mysql value as received from the database
-#[derive(Copy, Clone, Debug)]
+#[derive(Clone, Debug)]
 pub struct MysqlValue<'a> {
     raw: &'a [u8],
     tpe: MysqlType,
diff --git a/diesel/src/pg/backend.rs b/diesel/src/pg/backend.rs
index 79f833a898b6..ec56e04a76ec 100644
--- a/diesel/src/pg/backend.rs
+++ b/diesel/src/pg/backend.rs
@@ -140,7 +140,7 @@ impl SqlDialect for Pg {
 
     type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax;
     type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax;
-    type ArrayComparision = PgStyleArrayComparision;
+    type ArrayComparison = PgStyleArrayComparision;
 }
 
 impl DieselReserveSpecialization for Pg {}
diff --git a/diesel/src/pg/connection/cursor.rs b/diesel/src/pg/connection/cursor.rs
index bb9a4eccc284..cab624041f74 100644
--- a/diesel/src/pg/connection/cursor.rs
+++ b/diesel/src/pg/connection/cursor.rs
@@ -1,41 +1,32 @@
-use std::marker::PhantomData;
-use std::rc::Rc;
-
+use super::raw::RawConnection;
 use super::result::PgResult;
 use super::row::PgRow;
-use super::PgConnection;
+use std::rc::Rc;
 
-/// The type returned by various [`Connection`] methods.
-/// Acts as an iterator over `T`.
 #[allow(missing_debug_implementations)]
-pub struct Cursor<'a> {
+pub struct Cursor {
     current_row: usize,
     db_result: Rc<PgResult>,
-    // We referenze connection here so that
-    // we could possibly use the connection in future changes
-    // to cursor
-    // This may be required to conditionally implement
-    // loading items using libpqs single row mode
-    p: PhantomData<&'a mut PgConnection>,
 }
 
-impl Cursor<'_> {
-    pub(super) fn new(db_result: PgResult) -> Self {
-        Cursor {
+impl Cursor {
+    pub(super) fn new(result: PgResult, conn: &mut RawConnection) -> crate::QueryResult<Cursor> {
+        let next_res = conn.get_next_result()?;
+        debug_assert!(next_res.is_none());
+        Ok(Self {
             current_row: 0,
-            db_result: Rc::new(db_result),
-            p: PhantomData,
-        }
+            db_result: Rc::new(result),
+        })
     }
 }
 
-impl ExactSizeIterator for Cursor<'_> {
+impl ExactSizeIterator for Cursor {
     fn len(&self) -> usize {
         self.db_result.num_rows() - self.current_row
     }
 }
 
-impl Iterator for Cursor<'_> {
+impl Iterator for Cursor {
     type Item = crate::QueryResult<PgRow>;
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -66,112 +57,349 @@ impl Iterator for Cursor<'_> {
     }
 }
 
-#[test]
-fn fun_with_row_iters() {
-    crate::table! {
-        #[allow(unused_parens)]
-        users(id) {
-            id -> Integer,
-            name -> Text,
+/// The type returned by various [`Connection`] methods.
+/// Acts as an iterator over `T`.
+#[allow(missing_debug_implementations)]
+pub struct RowByRowCursor<'a> {
+    first_row: bool,
+    db_result: Rc<PgResult>,
+    conn: &'a mut super::ConnectionAndTransactionManager,
+}
+
+impl<'a> RowByRowCursor<'a> {
+    pub(super) fn new(
+        db_result: PgResult,
+        conn: &'a mut super::ConnectionAndTransactionManager,
+    ) -> Self {
+        RowByRowCursor {
+            first_row: true,
+            db_result: Rc::new(db_result),
+            conn,
+        }
+    }
+}
+
+impl Iterator for RowByRowCursor<'_> {
+    type Item = crate::QueryResult<PgRow>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if !self.first_row {
+            let get_next_result = super::update_transaction_manager_status(
+                self.conn.raw_connection.get_next_result(),
+                self.conn,
+            );
+            match get_next_result {
+                Ok(Some(res)) => {
+                    // we try to reuse the existing allocation here
+                    if let Some(old_res) = Rc::get_mut(&mut self.db_result) {
+                        *old_res = res;
+                    } else {
+                        self.db_result = Rc::new(res);
+                    }
+                }
+                Ok(None) => {
+                    return None;
+                }
+                Err(e) => return Some(Err(e)),
+            }
+        }
+        // This contains either 1 (for a row containing data) or 0 (for the last one) rows
+        if self.db_result.num_rows() > 0 {
+            debug_assert_eq!(self.db_result.num_rows(), 1);
+            self.first_row = false;
+            Some(Ok(self.db_result.clone().get_row(0)))
+        } else {
+            None
+        }
+    }
+}
+
+impl Drop for RowByRowCursor<'_> {
+    fn drop(&mut self) {
+        loop {
+            let res = super::update_transaction_manager_status(
+                self.conn.raw_connection.get_next_result(),
+                self.conn,
+            );
+            if matches!(res, Err(_) | Ok(None)) {
+                break;
+            }
         }
     }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::connection::DefaultLoadingMode;
+    use crate::pg::PgRowByRowLoadingMode;
+
+    #[test]
+    fn fun_with_row_iters() {
+        crate::table! {
+            #[allow(unused_parens)]
+            users(id) {
+                id -> Integer,
+                name -> Text,
+            }
+        }
 
-    use crate::deserialize::{FromSql, FromSqlRow};
-    use crate::pg::Pg;
-    use crate::prelude::*;
-    use crate::row::{Field, Row};
-    use crate::sql_types;
-
-    let conn = &mut crate::test_helpers::connection();
-
-    crate::sql_query(
-        "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
-    )
-    .execute(conn)
-    .unwrap();
-
-    crate::insert_into(users::table)
-        .values(vec![
-            (users::id.eq(1), users::name.eq("Sean")),
-            (users::id.eq(2), users::name.eq("Tess")),
-        ])
+        use crate::connection::LoadConnection;
+        use crate::deserialize::{FromSql, FromSqlRow};
+        use crate::pg::Pg;
+        use crate::prelude::*;
+        use crate::row::{Field, Row};
+        use crate::sql_types;
+
+        let conn = &mut crate::test_helpers::connection();
+
+        crate::sql_query(
+            "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
+        )
         .execute(conn)
         .unwrap();
 
-    let query = users::table.select((users::id, users::name));
+        crate::insert_into(users::table)
+            .values(vec![
+                (users::id.eq(1), users::name.eq("Sean")),
+                (users::id.eq(2), users::name.eq("Tess")),
+            ])
+            .execute(conn)
+            .unwrap();
+
+        let query = users::table.select((users::id, users::name));
+
+        let expected = vec![(1, String::from("Sean")), (2, String::from("Tess"))];
+
+        let row_iter = LoadConnection::<DefaultLoadingMode>::load(conn, &query).unwrap();
+        for (row, expected) in row_iter.zip(&expected) {
+            let row = row.unwrap();
 
-    let expected = vec![(1, String::from("Sean")), (2, String::from("Tess"))];
+            let deserialized = <(i32, String) as FromSqlRow<
+                (sql_types::Integer, sql_types::Text),
+                _,
+            >>::build_from_row(&row)
+            .unwrap();
 
-    let row_iter = conn.load(&query).unwrap();
-    for (row, expected) in row_iter.zip(&expected) {
-        let row = row.unwrap();
+            assert_eq!(&deserialized, expected);
+        }
+
+        {
+            let collected_rows = LoadConnection::<DefaultLoadingMode>::load(conn, &query)
+                .unwrap()
+                .collect::<Vec<_>>();
 
-        let deserialized = <(i32, String) as FromSqlRow<
-            (sql_types::Integer, sql_types::Text),
-            _,
-        >>::build_from_row(&row)
+            for (row, expected) in collected_rows.iter().zip(&expected) {
+                let deserialized = row
+                    .as_ref()
+                    .map(|row| {
+                        <(i32, String) as FromSqlRow<
+                                (sql_types::Integer, sql_types::Text),
+                            _,
+                            >>::build_from_row(row).unwrap()
+                    })
+                    .unwrap();
+
+                assert_eq!(&deserialized, expected);
+            }
+        }
+
+        let mut row_iter = LoadConnection::<DefaultLoadingMode>::load(conn, &query).unwrap();
+
+        let first_row = row_iter.next().unwrap().unwrap();
+        let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap());
+        let first_values = (first_fields.0.value(), first_fields.1.value());
+
+        let second_row = row_iter.next().unwrap().unwrap();
+        let second_fields = (second_row.get(0).unwrap(), second_row.get(1).unwrap());
+        let second_values = (second_fields.0.value(), second_fields.1.value());
+
+        assert!(row_iter.next().is_none());
+
+        assert_eq!(
+            <i32 as FromSql<sql_types::Integer, Pg>>::from_nullable_sql(first_values.0).unwrap(),
+            expected[0].0
+        );
+        assert_eq!(
+            <String as FromSql<sql_types::Text, Pg>>::from_nullable_sql(first_values.1).unwrap(),
+            expected[0].1
+        );
+
+        assert_eq!(
+            <i32 as FromSql<sql_types::Integer, Pg>>::from_nullable_sql(second_values.0).unwrap(),
+            expected[1].0
+        );
+        assert_eq!(
+            <String as FromSql<sql_types::Text, Pg>>::from_nullable_sql(second_values.1).unwrap(),
+            expected[1].1
+        );
+
+        let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap());
+        let first_values = (first_fields.0.value(), first_fields.1.value());
+
+        assert_eq!(
+            <i32 as FromSql<sql_types::Integer, Pg>>::from_nullable_sql(first_values.0).unwrap(),
+            expected[0].0
+        );
+        assert_eq!(
+            <String as FromSql<sql_types::Text, Pg>>::from_nullable_sql(first_values.1).unwrap(),
+            expected[0].1
+        );
+    }
+
+    #[test]
+    fn loading_modes_return_the_same_result() {
+        use crate::prelude::*;
+
+        crate::table! {
+            #[allow(unused_parens)]
+            users(id) {
+                id -> Integer,
+                name -> Text,
+            }
+        }
+
+        let conn = &mut crate::test_helpers::connection();
+
+        crate::sql_query(
+            "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
+        )
+        .execute(conn)
         .unwrap();
 
-        assert_eq!(&deserialized, expected);
+        crate::insert_into(users::table)
+            .values(vec![
+                (users::id.eq(1), users::name.eq("Sean")),
+                (users::id.eq(2), users::name.eq("Tess")),
+            ])
+            .execute(conn)
+            .unwrap();
+
+        let users_by_default_mode = users::table
+            .select(users::name)
+            .load_iter::<String, DefaultLoadingMode>(conn)
+            .unwrap()
+            .collect::<QueryResult<Vec<_>>>()
+            .unwrap();
+        let users_row_by_row = users::table
+            .select(users::name)
+            .load_iter::<String, PgRowByRowLoadingMode>(conn)
+            .unwrap()
+            .collect::<QueryResult<Vec<_>>>()
+            .unwrap();
+        assert_eq!(users_by_default_mode, users_row_by_row);
+        assert_eq!(users_by_default_mode, vec!["Sean", "Tess"]);
     }
 
-    {
-        let collected_rows = conn.load(&query).unwrap().collect::<Vec<_>>();
-
-        for (row, expected) in collected_rows.iter().zip(&expected) {
-            let deserialized = row
-                .as_ref()
-                .map(|row| {
-                    <(i32, String) as FromSqlRow<
-                            (sql_types::Integer, sql_types::Text),
-                        _,
-                        >>::build_from_row(row).unwrap()
-                })
-                .unwrap();
+    #[test]
+    fn fun_with_row_iters_row_by_row() {
+        crate::table! {
+            #[allow(unused_parens)]
+            users(id) {
+                id -> Integer,
+                name -> Text,
+            }
+        }
+
+        use crate::connection::LoadConnection;
+        use crate::deserialize::{FromSql, FromSqlRow};
+        use crate::pg::Pg;
+        use crate::prelude::*;
+        use crate::row::{Field, Row};
+        use crate::sql_types;
+
+        let conn = &mut crate::test_helpers::connection();
+
+        crate::sql_query(
+            "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
+        )
+        .execute(conn)
+        .unwrap();
+
+        crate::insert_into(users::table)
+            .values(vec![
+                (users::id.eq(1), users::name.eq("Sean")),
+                (users::id.eq(2), users::name.eq("Tess")),
+            ])
+            .execute(conn)
+            .unwrap();
+
+        let query = users::table.select((users::id, users::name));
+
+        let expected = vec![(1, String::from("Sean")), (2, String::from("Tess"))];
+
+        let row_iter = LoadConnection::<PgRowByRowLoadingMode>::load(conn, &query).unwrap();
+        for (row, expected) in row_iter.zip(&expected) {
+            let row = row.unwrap();
+
+            let deserialized = <(i32, String) as FromSqlRow<
+                (sql_types::Integer, sql_types::Text),
+                _,
+            >>::build_from_row(&row)
+            .unwrap();
 
             assert_eq!(&deserialized, expected);
         }
-    }
 
-    let mut row_iter = conn.load(&query).unwrap();
-
-    let first_row = row_iter.next().unwrap().unwrap();
-    let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap());
-    let first_values = (first_fields.0.value(), first_fields.1.value());
-
-    let second_row = row_iter.next().unwrap().unwrap();
-    let second_fields = (second_row.get(0).unwrap(), second_row.get(1).unwrap());
-    let second_values = (second_fields.0.value(), second_fields.1.value());
-
-    assert!(row_iter.next().is_none());
-
-    assert_eq!(
-        <i32 as FromSql<sql_types::Integer, Pg>>::from_nullable_sql(first_values.0).unwrap(),
-        expected[0].0
-    );
-    assert_eq!(
-        <String as FromSql<sql_types::Text, Pg>>::from_nullable_sql(first_values.1).unwrap(),
-        expected[0].1
-    );
-
-    assert_eq!(
-        <i32 as FromSql<sql_types::Integer, Pg>>::from_nullable_sql(second_values.0).unwrap(),
-        expected[1].0
-    );
-    assert_eq!(
-        <String as FromSql<sql_types::Text, Pg>>::from_nullable_sql(second_values.1).unwrap(),
-        expected[1].1
-    );
-
-    let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap());
-    let first_values = (first_fields.0.value(), first_fields.1.value());
-
-    assert_eq!(
-        <i32 as FromSql<sql_types::Integer, Pg>>::from_nullable_sql(first_values.0).unwrap(),
-        expected[0].0
-    );
-    assert_eq!(
-        <String as FromSql<sql_types::Text, Pg>>::from_nullable_sql(first_values.1).unwrap(),
-        expected[0].1
-    );
+        {
+            let collected_rows = LoadConnection::<PgRowByRowLoadingMode>::load(conn, &query)
+                .unwrap()
+                .collect::<Vec<_>>();
+
+            for (row, expected) in collected_rows.iter().zip(&expected) {
+                let deserialized = row
+                    .as_ref()
+                    .map(|row| {
+                        <(i32, String) as FromSqlRow<
+                                (sql_types::Integer, sql_types::Text),
+                            _,
+                            >>::build_from_row(row).unwrap()
+                    })
+                    .unwrap();
+
+                assert_eq!(&deserialized, expected);
+            }
+        }
+
+        let mut row_iter = LoadConnection::<PgRowByRowLoadingMode>::load(conn, &query).unwrap();
+
+        let first_row = row_iter.next().unwrap().unwrap();
+        let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap());
+        let first_values = (first_fields.0.value(), first_fields.1.value());
+
+        let second_row = row_iter.next().unwrap().unwrap();
+        let second_fields = (second_row.get(0).unwrap(), second_row.get(1).unwrap());
+        let second_values = (second_fields.0.value(), second_fields.1.value());
+
+        assert!(row_iter.next().is_none());
+
+        assert_eq!(
+            <i32 as FromSql<sql_types::Integer, Pg>>::from_nullable_sql(first_values.0).unwrap(),
+            expected[0].0
+        );
+        assert_eq!(
+            <String as FromSql<sql_types::Text, Pg>>::from_nullable_sql(first_values.1).unwrap(),
+            expected[0].1
+        );
+
+        assert_eq!(
+            <i32 as FromSql<sql_types::Integer, Pg>>::from_nullable_sql(second_values.0).unwrap(),
+            expected[1].0
+        );
+        assert_eq!(
+            <String as FromSql<sql_types::Text, Pg>>::from_nullable_sql(second_values.1).unwrap(),
+            expected[1].1
+        );
+
+        let first_fields = (first_row.get(0).unwrap(), first_row.get(1).unwrap());
+        let first_values = (first_fields.0.value(), first_fields.1.value());
+
+        assert_eq!(
+            <i32 as FromSql<sql_types::Integer, Pg>>::from_nullable_sql(first_values.0).unwrap(),
+            expected[0].0
+        );
+        assert_eq!(
+            <String as FromSql<sql_types::Text, Pg>>::from_nullable_sql(first_values.1).unwrap(),
+            expected[0].1
+        );
+    }
 }
diff --git a/diesel/src/pg/connection/mod.rs b/diesel/src/pg/connection/mod.rs
index c1a6cf3c8b44..90a4fc57ba89 100644
--- a/diesel/src/pg/connection/mod.rs
+++ b/diesel/src/pg/connection/mod.rs
@@ -4,14 +4,11 @@ mod result;
 mod row;
 mod stmt;
 
-use std::ffi::CString;
-use std::os::raw as libc;
-
 use self::cursor::*;
+use self::private::ConnectionAndTransactionManager;
 use self::raw::{PgTransactionStatus, RawConnection};
 use self::result::PgResult;
 use self::stmt::Statement;
-use crate::connection::commit_error_processor::{CommitErrorOutcome, CommitErrorProcessor};
 use crate::connection::statement_cache::{MaybeCached, StatementCache};
 use crate::connection::*;
 use crate::expression::QueryMetadata;
@@ -22,17 +19,104 @@ use crate::query_builder::*;
 use crate::result::ConnectionError::CouldntSetupConfiguration;
 use crate::result::*;
 use crate::RunQueryDsl;
+use std::ffi::CString;
+use std::os::raw as libc;
 
 /// The connection string expected by `PgConnection::establish`
 /// should be a PostgreSQL connection string, as documented at
 /// <https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING>
+///
+/// # Supported loading model implementations
+///
+/// * [`DefaultLoadingMode`]
+/// * [`PgRowByRowLoadingMode`]
+///
+/// If you are unsure which loading mode is the correct one for your application,
+/// you likely want to use the `DefaultLoadingMode` as that one offers
+/// generally better performance.
+///
+/// Due to the fact that `PgConnection` supports multiple loading modes
+/// it is **required** to always specify the used loading mode
+/// when calling [`RunQueryDsl::load_iter`]
+///
+/// ## `DefaultLoadingMode`
+///
+/// By using this mode `PgConnection` defaults to loading all response values at **once**
+/// and only performs deserialization afterward for the `DefaultLoadingMode`.
+/// Generally this mode will be more performant as it.
+///
+/// This loading mode allows users to perform hold more than one iterator at once using
+/// the same connection:
+/// ```rust
+/// # include!("../../doctest_setup.rs");
+/// #
+/// # fn main() {
+/// #     run_test().unwrap();
+/// # }
+/// #
+/// # fn run_test() -> QueryResult<()> {
+/// #     use schema::users;
+/// #     let connection = &mut establish_connection();
+/// use diesel::connection::DefaultLoadingMode;
+///
+/// let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
+/// let iter2 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
+///
+/// for r in iter1 {
+///     let (id, name) = r?;
+///     println!("Id: {} Name: {}", id, name);
+/// }
+///
+/// for r in iter2 {
+///     let (id, name) = r?;
+///     println!("Id: {} Name: {}", id, name);
+/// }
+/// #   Ok(())
+/// # }
+/// ```
+///
+/// ## `PgRowByRowLoadingMode`
+///
+/// By using this mode `PgConnection` defaults to loading each row of the result set
+/// sepreatly. This might be desired for huge result sets.
+///
+/// This loading mode **prevents** creating more than one iterator at once using
+/// the same connection. The following code is **not** allowed:
+///
+/// ```compile_fail
+/// # include!("../../doctest_setup.rs");
+/// #
+/// # fn main() {
+/// #     run_test().unwrap();
+/// # }
+/// #
+/// # fn run_test() -> QueryResult<()> {
+/// #     use schema::users;
+/// #     let connection = &mut establish_connection();
+/// use diesel::pg::PgRowByRowLoadingMode;
+///
+/// let iter1 = users::table.load_iter::<(i32, String), PgRowByRowLoadingMode>(connection)?;
+/// // creating a second iterator generates an compiler error
+/// let iter2 = users::table.load_iter::<(i32, String), PgRowByRowLoadingMode>(connection)?;
+///
+/// for r in iter1 {
+///     let (id, name) = r?;
+///     println!("Id: {} Name: {}", id, name);
+/// }
+///
+/// for r in iter2 {
+///     let (id, name) = r?;
+///     println!("Id: {} Name: {}", id, name);
+/// }
+/// #   Ok(())
+/// # }
+/// ```
 #[allow(missing_debug_implementations)]
 #[cfg(feature = "postgres")]
 pub struct PgConnection {
-    raw_connection: RawConnection,
-    transaction_state: AnsiTransactionManager,
     statement_cache: StatementCache<Pg, Statement>,
     metadata_cache: PgMetadataCache,
+    connection_and_transaction_manager: ConnectionAndTransactionManager,
 }
 
 unsafe impl Send for PgConnection {}
@@ -40,76 +124,42 @@ unsafe impl Send for PgConnection {}
 impl SimpleConnection for PgConnection {
     fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
         let query = CString::new(query)?;
-        let inner_result = unsafe { self.raw_connection.exec(query.as_ptr()) };
-        PgResult::new(inner_result?, &self.raw_connection)?;
+        let inner_result = unsafe {
+            self.connection_and_transaction_manager
+                .raw_connection
+                .exec(query.as_ptr())
+        };
+        update_transaction_manager_status(
+            inner_result.and_then(|raw_result| {
+                PgResult::new(
+                    raw_result,
+                    &self.connection_and_transaction_manager.raw_connection,
+                )
+            }),
+            &mut self.connection_and_transaction_manager,
+        )?;
         Ok(())
     }
 }
 
-impl<'conn, 'query> ConnectionGatWorkaround<'conn, 'query, Pg> for PgConnection {
-    type Cursor = Cursor<'conn>;
+/// A [`PgConnection`] specific loading mode to load rows one by one
+///
+/// See the documentation of [`PgConnection`] for details
+#[derive(Debug, Copy, Clone)]
+pub struct PgRowByRowLoadingMode;
+
+impl<'conn, 'query> ConnectionGatWorkaround<'conn, 'query, Pg, DefaultLoadingMode>
+    for PgConnection
+{
+    type Cursor = Cursor;
     type Row = self::row::PgRow;
 }
 
-impl CommitErrorProcessor for PgConnection {
-    fn process_commit_error(&self, error: Error) -> CommitErrorOutcome {
-        let transaction_depth = match self.transaction_state.status.transaction_depth() {
-            Ok(d) => d,
-            Err(e) => return CommitErrorOutcome::Throw(e),
-        };
-        let transaction_status = self.raw_connection.transaction_status();
-        if transaction_status == PgTransactionStatus::Unknown {
-            return CommitErrorOutcome::ThrowAndMarkManagerAsBroken(error);
-        }
-        if matches!(
-            error,
-            Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
-        ) {
-            return CommitErrorOutcome::Throw(error);
-        }
-        if let Some(transaction_depth) = transaction_depth {
-            match error {
-                Error::DatabaseError(DatabaseErrorKind::ReadOnlyTransaction, _)
-                | Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _)
-                    if transaction_depth.get() == 1 =>
-                {
-                    CommitErrorOutcome::RollbackAndThrow(error)
-                }
-                Error::DatabaseError(DatabaseErrorKind::Unknown, _)
-                    if transaction_status == PgTransactionStatus::InError
-                        && transaction_depth.get() > 1 =>
-                {
-                    CommitErrorOutcome::RollbackAndThrow(error)
-                }
-                Error::AlreadyInTransaction
-                | Error::DatabaseError(DatabaseErrorKind::CheckViolation, _)
-                | Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
-                | Error::DatabaseError(DatabaseErrorKind::ForeignKeyViolation, _)
-                | Error::DatabaseError(DatabaseErrorKind::NotNullViolation, _)
-                | Error::DatabaseError(DatabaseErrorKind::UnableToSendCommand, _)
-                | Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _)
-                | Error::DatabaseError(DatabaseErrorKind::Unknown, _)
-                | Error::DatabaseError(DatabaseErrorKind::ReadOnlyTransaction, _)
-                | Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _)
-                | Error::DeserializationError(_)
-                | Error::InvalidCString(_)
-                | Error::NotFound
-                | Error::QueryBuilderError(_)
-                | Error::RollbackError(_)
-                | Error::NotInTransaction
-                | Error::RollbackTransaction
-                | Error::SerializationError(_)
-                | Error::BrokenTransaction
-                | Error::CommitTransactionFailed { .. } => CommitErrorOutcome::Throw(error),
-            }
-        } else {
-            unreachable!(
-                "Calling commit_error_processor outside of a transaction is implementation error.\
-                 If you ever see this error message outside implementing a custom transaction manager\
-                 please open a new issue at diesels issue tracker."
-            )
-        }
-    }
+impl<'conn, 'query> ConnectionGatWorkaround<'conn, 'query, Pg, PgRowByRowLoadingMode>
+    for PgConnection
+{
+    type Cursor = RowByRowCursor<'conn>;
+    type Row = self::row::PgRow;
 }
 
 impl Connection for PgConnection {
@@ -119,8 +169,10 @@ impl Connection for PgConnection {
     fn establish(database_url: &str) -> ConnectionResult<PgConnection> {
         RawConnection::establish(database_url).and_then(|raw_conn| {
             let mut conn = PgConnection {
-                raw_connection: raw_conn,
-                transaction_state: AnsiTransactionManager::default(),
+                connection_and_transaction_manager: ConnectionAndTransactionManager {
+                    raw_connection: raw_conn,
+                    transaction_state: AnsiTransactionManager::default(),
+                },
                 statement_cache: StatementCache::new(),
                 metadata_cache: PgMetadataCache::new(),
             };
@@ -129,38 +181,50 @@ impl Connection for PgConnection {
             Ok(conn)
         })
     }
-
-    fn load<'conn, 'query, T>(
-        &'conn mut self,
-        source: T,
-    ) -> QueryResult<LoadRowIter<'conn, 'query, Self, Self::Backend>>
-    where
-        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
-        Self::Backend: QueryMetadata<T::SqlType>,
-    {
-        self.with_prepared_query(&source, |stmt, params, conn| {
-            let result = stmt.execute(conn, &params)?;
-            let cursor = Cursor::new(result);
-
-            Ok(cursor)
-        })
-    }
-
-    #[doc(hidden)]
     fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
     where
         T: QueryFragment<Pg> + QueryId,
     {
-        self.with_prepared_query(source, |query, params, conn| {
-            query.execute(conn, &params).map(|r| r.rows_affected())
-        })
+        update_transaction_manager_status(
+            self.with_prepared_query(source, |query, params, conn| {
+                let res = query
+                    .execute(&mut conn.raw_connection, &params, false)
+                    .map(|r| r.rows_affected());
+                // according to https://www.postgresql.org/docs/current/libpq-async.html
+                // `PQgetResult` needs to be called till a null pointer is returned
+                while conn.raw_connection.get_next_result()?.is_some() {}
+                res
+            }),
+            &mut self.connection_and_transaction_manager,
+        )
     }
 
     fn transaction_state(&mut self) -> &mut AnsiTransactionManager
     where
         Self: Sized,
     {
-        &mut self.transaction_state
+        &mut self.connection_and_transaction_manager.transaction_state
+    }
+}
+
+impl<B> LoadConnection<B> for PgConnection
+where
+    Self: self::private::PgLoadingMode<B>,
+{
+    fn load<'conn, 'query, T>(
+        &'conn mut self,
+        source: T,
+    ) -> QueryResult<LoadRowIter<'conn, 'query, Self, Self::Backend, B>>
+    where
+        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
+        Self::Backend: QueryMetadata<T::SqlType>,
+    {
+        self.with_prepared_query(&source, |stmt, params, conn| {
+            use self::private::PgLoadingMode;
+            let result = stmt.execute(&mut conn.raw_connection, &params, Self::USE_ROW_BY_ROW_MODE);
+            let result = update_transaction_manager_status(result, conn)?;
+            Self::get_cursor(conn, result)
+        })
     }
 }
 
@@ -170,6 +234,45 @@ impl GetPgMetadataCache for PgConnection {
     }
 }
 
+#[inline(always)]
+fn update_transaction_manager_status<T>(
+    query_result: QueryResult<T>,
+    conn: &mut ConnectionAndTransactionManager,
+) -> QueryResult<T> {
+    if let Err(Error::DatabaseError { .. }) = query_result {
+        /// avoid monomorphizing for every result type - this part will not be inlined
+        fn non_generic_inner(conn: &mut ConnectionAndTransactionManager) {
+            let raw_conn: &mut RawConnection = &mut conn.raw_connection;
+            let tm: &mut AnsiTransactionManager = &mut conn.transaction_state;
+            if tm.status.is_not_broken_and_in_transaction() {
+                // libpq keeps track of the transaction status internally, and that is accessible
+                // via `transaction_status`. We can use that to update the AnsiTransactionManager
+                // status
+                match raw_conn.transaction_status() {
+                    PgTransactionStatus::InError => {
+                        tm.status.set_top_level_transaction_requires_rollback()
+                    }
+                    PgTransactionStatus::Unknown => tm.status.set_in_error(),
+                    PgTransactionStatus::Idle => {
+                        // This may repair the transaction manager
+                        tm.status = TransactionManagerStatus::Valid(Default::default())
+                    }
+                    PgTransactionStatus::InTransaction => {
+                        let transaction_status = &mut tm.status;
+                        if !matches!(transaction_status, TransactionManagerStatus::Valid(valid_tm) if valid_tm.transaction_depth().is_some())
+                        {
+                            transaction_status.set_in_error()
+                        }
+                    }
+                    PgTransactionStatus::Active => {}
+                }
+            }
+        }
+        non_generic_inner(conn)
+    }
+    query_result
+}
+
 #[cfg(feature = "r2d2")]
 impl crate::r2d2::R2D2Connection for PgConnection {
     fn ping(&mut self) -> QueryResult<()> {
@@ -177,11 +280,20 @@ impl crate::r2d2::R2D2Connection for PgConnection {
     }
 
     fn is_broken(&mut self) -> bool {
-        self.transaction_state
+        match self
+            .connection_and_transaction_manager
+            .transaction_state
             .status
             .transaction_depth()
-            .map(|d| d.is_none())
-            .unwrap_or(true)
+        {
+            // all transactions are closed
+            // so we don't consider this connection broken
+            Ok(None) => false,
+            // The transaction manager is in an error state
+            // or contains an open transaction
+            // Therefore we consider this connection broken
+            Err(_) | Ok(Some(_)) => true,
+        }
     }
 }
 
@@ -219,7 +331,7 @@ impl PgConnection {
         f: impl FnOnce(
             MaybeCached<'_, Statement>,
             Vec<Option<Vec<u8>>>,
-            &'conn mut RawConnection,
+            &'conn mut ConnectionAndTransactionManager,
         ) -> QueryResult<R>,
     ) -> QueryResult<R> {
         let mut bind_collector = RawBytesBindCollector::<Pg>::new();
@@ -229,23 +341,24 @@ impl PgConnection {
 
         let cache_len = self.statement_cache.len();
         let cache = &mut self.statement_cache;
-        let raw_conn = &mut self.raw_connection;
+        let conn = &mut self.connection_and_transaction_manager.raw_connection;
         let query = cache.cached_statement(source, &Pg, &metadata, |sql, _| {
             let query_name = if source.is_safe_to_cache_prepared(&Pg)? {
                 Some(format!("__diesel_stmt_{}", cache_len))
             } else {
                 None
             };
-            Statement::prepare(raw_conn, sql, query_name.as_deref(), &metadata)
+            Statement::prepare(conn, sql, query_name.as_deref(), &metadata)
         });
 
-        f(query?, binds, raw_conn)
+        f(query?, binds, &mut self.connection_and_transaction_manager)
     }
 
     fn set_config_options(&mut self) -> QueryResult<()> {
         crate::sql_query("SET TIME ZONE 'UTC'").execute(self)?;
         crate::sql_query("SET CLIENT_ENCODING TO 'UTF8'").execute(self)?;
-        self.raw_connection
+        self.connection_and_transaction_manager
+            .raw_connection
             .set_notice_processor(noop_notice_processor);
         Ok(())
     }
@@ -253,6 +366,54 @@ impl PgConnection {
 
 extern "C" fn noop_notice_processor(_: *mut libc::c_void, _message: *const libc::c_char) {}
 
+mod private {
+    use super::*;
+
+    #[allow(missing_debug_implementations)]
+    pub struct ConnectionAndTransactionManager {
+        pub(super) raw_connection: RawConnection,
+        pub(super) transaction_state: AnsiTransactionManager,
+    }
+
+    pub trait PgLoadingMode<B>
+    where
+        for<'conn, 'query> Self: ConnectionGatWorkaround<'conn, 'query, Pg, B>,
+    {
+        const USE_ROW_BY_ROW_MODE: bool;
+
+        fn get_cursor<'conn, 'query>(
+            raw_connection: &'conn mut ConnectionAndTransactionManager,
+            result: PgResult,
+        ) -> QueryResult<<Self as ConnectionGatWorkaround<'conn, 'query, Pg, B>>::Cursor>;
+    }
+
+    impl PgLoadingMode<DefaultLoadingMode> for PgConnection {
+        const USE_ROW_BY_ROW_MODE: bool = false;
+
+        fn get_cursor<'conn, 'query>(
+            conn: &'conn mut ConnectionAndTransactionManager,
+            result: PgResult,
+        ) -> QueryResult<
+            <Self as ConnectionGatWorkaround<'conn, 'query, Pg, DefaultLoadingMode>>::Cursor,
+        > {
+            update_transaction_manager_status(Cursor::new(result, &mut conn.raw_connection), conn)
+        }
+    }
+
+    impl PgLoadingMode<PgRowByRowLoadingMode> for PgConnection {
+        const USE_ROW_BY_ROW_MODE: bool = true;
+
+        fn get_cursor<'conn, 'query>(
+            raw_connection: &'conn mut ConnectionAndTransactionManager,
+            result: PgResult,
+        ) -> QueryResult<
+            <Self as ConnectionGatWorkaround<'conn, 'query, Pg, PgRowByRowLoadingMode>>::Cursor,
+        > {
+            Ok(RowByRowCursor::new(result, raw_connection))
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     extern crate dotenvy;
@@ -270,12 +431,8 @@ mod tests {
         let query =
             crate::sql_query("SELECT not_existent FROM also_not_there;").execute(connection);
 
-        if let Err(err) = query {
-            if let DatabaseError(_, string) = err {
-                assert_eq!(Some(26), string.statement_position());
-            } else {
-                unreachable!();
-            }
+        if let Err(DatabaseError(_, string)) = query {
+            assert_eq!(Some(26), string.statement_position());
         } else {
             unreachable!();
         }
@@ -364,14 +521,14 @@ mod tests {
         let insert = query
             .insert_into(users::table)
             .into_columns((users::id, users::name));
-        assert_eq!(true, insert.execute(connection).is_ok());
+        assert!(insert.execute(connection).is_ok());
         assert_eq!(1, connection.statement_cache.len());
 
         let query = users::table.filter(users::id.eq(42)).into_boxed();
         let insert = query
             .insert_into(users::table)
             .into_columns((users::id, users::name));
-        assert_eq!(true, insert.execute(connection).is_ok());
+        assert!(insert.execute(connection).is_ok());
         assert_eq!(2, connection.statement_cache.len());
     }
 
@@ -389,7 +546,7 @@ mod tests {
         let insert =
             crate::insert_into(users::table).values((users::id.eq(42), users::name.eq("Foo")));
 
-        assert_eq!(true, insert.execute(connection).is_ok());
+        assert!(insert.execute(connection).is_ok());
         assert_eq!(1, connection.statement_cache.len());
     }
 
@@ -407,7 +564,7 @@ mod tests {
         let insert = crate::insert_into(users::table)
             .values(vec![(users::id.eq(42), users::name.eq("Foo"))]);
 
-        assert_eq!(true, insert.execute(connection).is_ok());
+        assert!(insert.execute(connection).is_ok());
         assert_eq!(0, connection.statement_cache.len());
     }
 
@@ -425,7 +582,7 @@ mod tests {
         let insert =
             crate::insert_into(users::table).values([(users::id.eq(42), users::name.eq("Foo"))]);
 
-        assert_eq!(true, insert.execute(connection).is_ok());
+        assert!(insert.execute(connection).is_ok());
         assert_eq!(1, connection.statement_cache.len());
     }
 
@@ -506,7 +663,7 @@ mod tests {
             assert!(query_result.is_err());
             assert_eq!(
                 PgTransactionStatus::InError,
-                conn.raw_connection.transaction_status()
+                conn.connection_and_transaction_manager.raw_connection.transaction_status()
             );
             query_result
         });
@@ -518,7 +675,9 @@ mod tests {
         );
         assert_eq!(
             PgTransactionStatus::Idle,
-            conn.raw_connection.transaction_status()
+            conn.connection_and_transaction_manager
+                .raw_connection
+                .transaction_status()
         );
     }
 
@@ -564,14 +723,16 @@ mod tests {
             assert!(query_result.is_ok());
             assert_eq!(
                 PgTransactionStatus::InTransaction,
-                conn.raw_connection.transaction_status()
+                conn.connection_and_transaction_manager.raw_connection.transaction_status()
             );
             query_result
         });
         assert!(result.is_ok());
         assert_eq!(
             PgTransactionStatus::Idle,
-            conn.raw_connection.transaction_status()
+            conn.connection_and_transaction_manager
+                .raw_connection
+                .transaction_status()
         );
         assert_eq!(
             None,
@@ -582,10 +743,13 @@ mod tests {
     }
 
     #[test]
+    // This function uses collect with an side effect (spawning threads)
+    // so this is a false positive from clippy
+    #[allow(clippy::needless_collect)]
     fn postgres_transaction_depth_is_tracked_properly_on_serialization_failure() {
         use crate::pg::connection::raw::PgTransactionStatus;
         use crate::result::DatabaseErrorKind::SerializationFailure;
-        use crate::result::Error::{self, DatabaseError};
+        use crate::result::Error::DatabaseError;
         use crate::*;
         use std::sync::{Arc, Barrier};
         use std::thread;
@@ -655,7 +819,7 @@ mod tests {
                     });
                     assert_eq!(
                         PgTransactionStatus::Idle,
-                        conn.raw_connection.transaction_status()
+                        conn.connection_and_transaction_manager.raw_connection.transaction_status()
                     );
 
                     assert_eq!(None, <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
@@ -673,26 +837,26 @@ mod tests {
 
         assert!(matches!(results[0], Ok(_)), "Got {:?} instead", results);
         assert!(
-            matches!(
-                &results[1],
-                Err(Error::CommitTransactionFailed {
-                    ref commit_error, ..
-                }) if matches!(&**commit_error, DatabaseError(SerializationFailure, _))
-            ),
+            matches!(&results[1], Err(DatabaseError(SerializationFailure, _))),
             "Got {:?} instead",
             results
         );
         assert_eq!(
             PgTransactionStatus::Idle,
-            conn.raw_connection.transaction_status()
+            conn.connection_and_transaction_manager
+                .raw_connection
+                .transaction_status()
         );
     }
 
     #[test]
+    // This function uses collect with an side effect (spawning threads)
+    // so this is a false positive from clippy
+    #[allow(clippy::needless_collect)]
     fn postgres_transaction_depth_is_tracked_properly_on_nested_serialization_failure() {
         use crate::pg::connection::raw::PgTransactionStatus;
         use crate::result::DatabaseErrorKind::SerializationFailure;
-        use crate::result::Error::{self, DatabaseError};
+        use crate::result::Error::DatabaseError;
         use crate::*;
         use std::sync::{Arc, Barrier};
         use std::thread;
@@ -765,13 +929,13 @@ mod tests {
                         assert_eq!(NonZeroU32::new(1), <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
                         assert_eq!(
                             PgTransactionStatus::InTransaction,
-                            conn.raw_connection.transaction_status()
+                            conn.connection_and_transaction_manager.raw_connection.transaction_status()
                         );
                         r
                     });
                     assert_eq!(
                         PgTransactionStatus::Idle,
-                        conn.raw_connection.transaction_status()
+                        conn.connection_and_transaction_manager.raw_connection.transaction_status()
                     );
 
                     assert_eq!(None, <AnsiTransactionManager as TransactionManager<PgConnection>>::transaction_manager_status_mut(conn).transaction_depth().expect("Transaction depth"));
@@ -789,18 +953,15 @@ mod tests {
 
         assert!(matches!(results[0], Ok(_)), "Got {:?} instead", results);
         assert!(
-            matches!(
-                &results[1],
-                Err(Error::CommitTransactionFailed {
-                    ref commit_error, ..
-                }) if matches!(&**commit_error, DatabaseError(SerializationFailure, _))
-            ),
+            matches!(&results[1], Err(DatabaseError(SerializationFailure, _))),
             "Got {:?} instead",
             results
         );
         assert_eq!(
             PgTransactionStatus::Idle,
-            conn.raw_connection.transaction_status()
+            conn.connection_and_transaction_manager
+                .raw_connection
+                .transaction_status()
         );
     }
 
@@ -835,7 +996,7 @@ mod tests {
             assert!(result.is_ok());
             assert_eq!(
                 PgTransactionStatus::InTransaction,
-                conn.raw_connection.transaction_status()
+                conn.connection_and_transaction_manager.raw_connection.transaction_status()
             );
             Ok(())
         });
@@ -847,7 +1008,9 @@ mod tests {
         );
         assert_eq!(
             PgTransactionStatus::Idle,
-            conn.raw_connection.transaction_status()
+            conn.connection_and_transaction_manager
+                .raw_connection
+                .transaction_status()
         );
         assert!(result.is_err());
     }
@@ -909,7 +1072,7 @@ mod tests {
             assert!(result.is_ok());
             assert_eq!(
                 PgTransactionStatus::InTransaction,
-                conn.raw_connection.transaction_status()
+                conn.connection_and_transaction_manager.raw_connection.transaction_status()
             );
             Ok(())
         });
@@ -921,7 +1084,9 @@ mod tests {
         );
         assert_eq!(
             PgTransactionStatus::Idle,
-            conn.raw_connection.transaction_status()
+            conn.connection_and_transaction_manager
+                .raw_connection
+                .transaction_status()
         );
         assert!(result.is_err());
     }
@@ -990,7 +1155,7 @@ mod tests {
             assert!(inner_result.is_err());
             assert_eq!(
                 PgTransactionStatus::InTransaction,
-                conn.raw_connection.transaction_status()
+                conn.connection_and_transaction_manager.raw_connection.transaction_status()
             );
             Ok(())
         });
@@ -1002,7 +1167,9 @@ mod tests {
         );
         assert_eq!(
             PgTransactionStatus::Idle,
-            conn.raw_connection.transaction_status()
+            conn.connection_and_transaction_manager
+                .raw_connection
+                .transaction_status()
         );
         assert!(result.is_ok(), "Expected success, got {:?}", result);
     }
@@ -1046,7 +1213,7 @@ mod tests {
             assert!(inner_result.is_err());
             assert_eq!(
                 PgTransactionStatus::InTransaction,
-                conn.raw_connection.transaction_status()
+                conn.connection_and_transaction_manager.raw_connection.transaction_status()
             );
             assert_eq!(
                 NonZeroU32::new(1),
@@ -1064,7 +1231,9 @@ mod tests {
         );
         assert_eq!(
             PgTransactionStatus::Idle,
-            conn.raw_connection.transaction_status()
+            conn.connection_and_transaction_manager
+                .raw_connection
+                .transaction_status()
         );
         assert!(result.is_ok());
     }
diff --git a/diesel/src/pg/connection/raw.rs b/diesel/src/pg/connection/raw.rs
index f13a6e7555da..a7483cfa9bac 100644
--- a/diesel/src/pg/connection/raw.rs
+++ b/diesel/src/pg/connection/raw.rs
@@ -10,6 +10,8 @@ use std::{ptr, str};
 
 use crate::result::*;
 
+use super::result::PgResult;
+
 #[allow(missing_debug_implementations, missing_copy_implementations)]
 pub(super) struct RawConnection {
     internal_connection: NonNull<PGconn>,
@@ -61,7 +63,7 @@ impl RawConnection {
         RawResult::new(PQexec(self.internal_connection.as_ptr(), query), self)
     }
 
-    pub(super) unsafe fn exec_prepared(
+    pub(super) unsafe fn send_query_prepared(
         &self,
         stmt_name: *const libc::c_char,
         param_count: libc::c_int,
@@ -69,8 +71,8 @@ impl RawConnection {
         param_lengths: *const libc::c_int,
         param_formats: *const libc::c_int,
         result_format: libc::c_int,
-    ) -> QueryResult<RawResult> {
-        let ptr = PQexecPrepared(
+    ) -> QueryResult<()> {
+        let res = PQsendQueryPrepared(
             self.internal_connection.as_ptr(),
             stmt_name,
             param_count,
@@ -79,7 +81,14 @@ impl RawConnection {
             param_formats,
             result_format,
         );
-        RawResult::new(ptr, self)
+        if res == 1 {
+            Ok(())
+        } else {
+            Err(Error::DatabaseError(
+                DatabaseErrorKind::UnableToSendCommand,
+                Box::new(self.last_error_message()),
+            ))
+        }
     }
 
     pub(super) unsafe fn prepare(
@@ -106,6 +115,28 @@ impl RawConnection {
     pub(super) fn get_status(&self) -> ConnStatusType {
         unsafe { PQstatus(self.internal_connection.as_ptr()) }
     }
+
+    pub(crate) fn get_next_result(&self) -> Result<Option<PgResult>, Error> {
+        let res = unsafe { PQgetResult(self.internal_connection.as_ptr()) };
+        if res.is_null() {
+            Ok(None)
+        } else {
+            let raw = RawResult::new(res, self)?;
+            Ok(Some(PgResult::new(raw, self)?))
+        }
+    }
+
+    pub(crate) fn enable_row_by_row_mode(&self) -> QueryResult<()> {
+        let res = unsafe { PQsetSingleRowMode(self.internal_connection.as_ptr()) };
+        if res == 1 {
+            Ok(())
+        } else {
+            Err(Error::DatabaseError(
+                DatabaseErrorKind::Unknown,
+                Box::new(self.last_error_message()),
+            ))
+        }
+    }
 }
 
 /// Represents the current in-transaction status of the connection
diff --git a/diesel/src/pg/connection/result.rs b/diesel/src/pg/connection/result.rs
index f751b861ad76..3036c5d7ec1d 100644
--- a/diesel/src/pg/connection/result.rs
+++ b/diesel/src/pg/connection/result.rs
@@ -12,7 +12,8 @@ use super::row::PgRow;
 use crate::result::{DatabaseErrorInformation, DatabaseErrorKind, Error, QueryResult};
 use crate::util::OnceCell;
 
-pub(crate) struct PgResult {
+#[allow(missing_debug_implementations)]
+pub struct PgResult {
     internal_result: RawResult,
     column_count: usize,
     row_count: usize,
@@ -27,7 +28,9 @@ impl PgResult {
     pub(super) fn new(internal_result: RawResult, conn: &RawConnection) -> QueryResult<Self> {
         let result_status = unsafe { PQresultStatus(internal_result.as_ptr()) };
         match result_status {
-            ExecStatusType::PGRES_COMMAND_OK | ExecStatusType::PGRES_TUPLES_OK => {
+            ExecStatusType::PGRES_SINGLE_TUPLE
+            | ExecStatusType::PGRES_COMMAND_OK
+            | ExecStatusType::PGRES_TUPLES_OK => {
                 let column_count = unsafe { PQnfields(internal_result.as_ptr()) as usize };
                 let row_count = unsafe { PQntuples(internal_result.as_ptr()) as usize };
                 Ok(PgResult {
diff --git a/diesel/src/pg/connection/stmt/mod.rs b/diesel/src/pg/connection/stmt/mod.rs
index 8587b80019de..816eeab96eb7 100644
--- a/diesel/src/pg/connection/stmt/mod.rs
+++ b/diesel/src/pg/connection/stmt/mod.rs
@@ -20,6 +20,7 @@ impl Statement {
         &self,
         raw_connection: &mut RawConnection,
         param_data: &[Option<Vec<u8>>],
+        row_by_row: bool,
     ) -> QueryResult<PgResult> {
         let params_pointer = param_data
             .iter()
@@ -33,8 +34,8 @@ impl Statement {
             .iter()
             .map(|data| data.as_ref().map(|d| d.len() as libc::c_int).unwrap_or(0))
             .collect::<Vec<_>>();
-        let internal_res = unsafe {
-            raw_connection.exec_prepared(
+        unsafe {
+            raw_connection.send_query_prepared(
                 self.name.as_ptr(),
                 params_pointer.len() as libc::c_int,
                 params_pointer.as_ptr(),
@@ -42,9 +43,11 @@ impl Statement {
                 self.param_formats.as_ptr(),
                 1,
             )
-        };
-
-        PgResult::new(internal_res?, raw_connection)
+        }?;
+        if row_by_row {
+            raw_connection.enable_row_by_row_mode()?;
+        }
+        Ok(raw_connection.get_next_result()?.expect("Is never none"))
     }
 
     pub(super) fn prepare(
diff --git a/diesel/src/pg/expression/expression_methods.rs b/diesel/src/pg/expression/expression_methods.rs
index 939e1403e7ca..e6ceed27fa4d 100644
--- a/diesel/src/pg/expression/expression_methods.rs
+++ b/diesel/src/pg/expression/expression_methods.rs
@@ -10,7 +10,8 @@ use crate::dsl;
 use crate::expression::grouped::Grouped;
 use crate::expression::operators::{Asc, Desc};
 use crate::expression::{AsExpression, Expression, IntoSql, TypedExpressionType};
-use crate::sql_types::{Array, Inet, Integer, Jsonb, SqlType, Text, VarChar};
+use crate::pg::expression::expression_methods::private::BinaryOrNullableBinary;
+use crate::sql_types::{Array, Binary, Inet, Integer, Jsonb, SqlType, Text, VarChar};
 use crate::EscapeExpressionMethods;
 
 /// PostgreSQL specific methods which are present on all expressions.
@@ -2177,9 +2178,179 @@ where
 {
 }
 
+/// PostgreSQL specific methods present on Binary expressions.
+#[cfg(feature = "postgres_backend")]
+pub trait PgBinaryExpressionMethods: Expression + Sized {
+    /// Concatenates two PostgreSQL byte arrays using the `||` operator.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// # include!("../../doctest_setup.rs");
+    /// #
+    /// # table! {
+    /// #     users {
+    /// #         id -> Integer,
+    /// #         name -> Binary,
+    /// #         hair_color -> Nullable<Binary>,
+    /// #     }
+    /// # }
+    /// #
+    /// # fn main() {
+    /// #     use self::users::dsl::*;
+    /// #     use diesel::insert_into;
+    /// #
+    /// #     let connection = &mut connection_no_data();
+    /// #     diesel::sql_query("CREATE TABLE users (
+    /// #         id INTEGER PRIMARY KEY,
+    /// #         name BYTEA NOT NULL,
+    /// #         hair_color BYTEA
+    /// #     )").execute(connection).unwrap();
+    /// #
+    /// #     insert_into(users)
+    /// #         .values(&vec![
+    /// #             (id.eq(1), name.eq("Sean".as_bytes()), Some(hair_color.eq(Some("Green".as_bytes())))),
+    /// #             (id.eq(2), name.eq("Tess".as_bytes()), None),
+    /// #         ])
+    /// #         .execute(connection)
+    /// #         .unwrap();
+    /// #
+    /// let names = users.select(name.concat(" the Greatest".as_bytes())).load(connection);
+    /// let expected_names = vec![
+    ///     b"Sean the Greatest".to_vec(),
+    ///     b"Tess the Greatest".to_vec()
+    /// ];
+    /// assert_eq!(Ok(expected_names), names);
+    ///
+    /// // If the value is nullable, the output will be nullable
+    /// let names = users.select(hair_color.concat("ish".as_bytes())).load(connection);
+    /// let expected_names = vec![
+    ///     Some(b"Greenish".to_vec()),
+    ///     None,
+    /// ];
+    /// assert_eq!(Ok(expected_names), names);
+    /// # }
+    /// ```
+    fn concat<T>(self, other: T) -> dsl::ConcatBinary<Self, T>
+    where
+        Self::SqlType: SqlType,
+        T: AsExpression<Binary>,
+    {
+        Grouped(ConcatBinary::new(self, other.as_expression()))
+    }
+
+    /// Creates a PostgreSQL binary `LIKE` expression.
+    ///
+    /// This method is case sensitive. There is no case-insensitive
+    /// equivalent as of PostgreSQL 14.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # include!("../../doctest_setup.rs");
+    /// #
+    /// # table! {
+    /// #     users {
+    /// #         id -> Integer,
+    /// #         name -> Binary,
+    /// #     }
+    /// # }
+    /// #
+    /// # fn main() {
+    /// #     use self::users::dsl::*;
+    /// #     use diesel::insert_into;
+    /// #
+    /// #     let connection = &mut connection_no_data();
+    /// #     diesel::sql_query("CREATE TABLE users (
+    /// #         id INTEGER PRIMARY KEY,
+    /// #         name BYTEA NOT NULL
+    /// #     )").execute(connection).unwrap();
+    /// #
+    /// #     insert_into(users)
+    /// #         .values(&vec![
+    /// #             (id.eq(1), name.eq("Sean".as_bytes())),
+    /// #             (id.eq(2), name.eq("Tess".as_bytes()))
+    /// #         ])
+    /// #         .execute(connection)
+    /// #         .unwrap();
+    /// #
+    /// let starts_with_s = users
+    ///     .select(name)
+    ///     .filter(name.like(b"S%".to_vec()))
+    ///     .load(connection);
+    /// assert_eq!(Ok(vec![b"Sean".to_vec()]), starts_with_s);
+    /// # }
+    /// ```
+    fn like<T>(self, other: T) -> dsl::LikeBinary<Self, T>
+    where
+        Self::SqlType: SqlType,
+        T: AsExpression<Binary>,
+    {
+        Grouped(LikeBinary::new(self, other.as_expression()))
+    }
+
+    /// Creates a PostgreSQL binary `LIKE` expression.
+    ///
+    /// This method is case sensitive. There is no case-insensitive
+    /// equivalent as of PostgreSQL 14.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # include!("../../doctest_setup.rs");
+    /// #
+    /// # table! {
+    /// #     users {
+    /// #         id -> Integer,
+    /// #         name -> Binary,
+    /// #     }
+    /// # }
+    /// #
+    /// # fn main() {
+    /// #     use self::users::dsl::*;
+    /// #     use diesel::insert_into;
+    /// #
+    /// #     let connection = &mut connection_no_data();
+    /// #     diesel::sql_query("CREATE TABLE users (
+    /// #         id INTEGER PRIMARY KEY,
+    /// #         name BYTEA NOT NULL
+    /// #     )").execute(connection).unwrap();
+    /// #
+    /// #     insert_into(users)
+    /// #         .values(&vec![
+    /// #             (id.eq(1), name.eq("Sean".as_bytes())),
+    /// #             (id.eq(2), name.eq("Tess".as_bytes()))
+    /// #         ])
+    /// #         .execute(connection)
+    /// #         .unwrap();
+    /// #
+    /// let starts_with_s = users
+    ///     .select(name)
+    ///     .filter(name.not_like(b"S%".to_vec()))
+    ///     .load(connection);
+    /// assert_eq!(Ok(vec![b"Tess".to_vec()]), starts_with_s);
+    /// # }
+    /// ```
+    fn not_like<T>(self, other: T) -> dsl::NotLikeBinary<Self, T>
+    where
+        Self::SqlType: SqlType,
+        T: AsExpression<Binary>,
+    {
+        Grouped(NotLikeBinary::new(self, other.as_expression()))
+    }
+}
+
+#[doc(hidden)]
+impl<T> PgBinaryExpressionMethods for T
+where
+    T: Expression,
+    T::SqlType: BinaryOrNullableBinary,
+{
+}
+
 mod private {
     use crate::sql_types::{
-        Array, Cidr, Inet, Integer, Json, Jsonb, Nullable, Range, SqlType, Text,
+        Array, Binary, Cidr, Inet, Integer, Json, Jsonb, Nullable, Range, SqlType, Text,
     };
     use crate::{Expression, IntoSql};
 
@@ -2361,4 +2532,9 @@ mod private {
     pub trait TextOrInteger {}
     impl TextOrInteger for Text {}
     impl TextOrInteger for Integer {}
+
+    pub trait BinaryOrNullableBinary {}
+
+    impl BinaryOrNullableBinary for Binary {}
+    impl BinaryOrNullableBinary for Nullable<Binary> {}
 }
diff --git a/diesel/src/pg/expression/extensions/interval_dsl.rs b/diesel/src/pg/expression/extensions/interval_dsl.rs
index 3d2c0d52c06f..c9fb66eee254 100644
--- a/diesel/src/pg/expression/extensions/interval_dsl.rs
+++ b/diesel/src/pg/expression/extensions/interval_dsl.rs
@@ -242,6 +242,9 @@ impl IntervalDsl for f64 {
 }
 
 #[cfg(test)]
+// those macros define nested function
+// that's fine for this test code
+#[allow(clippy::items_after_statements)]
 mod tests {
     extern crate dotenvy;
     extern crate quickcheck;
diff --git a/diesel/src/pg/expression/helper_types.rs b/diesel/src/pg/expression/helper_types.rs
index 374058ad5db9..be3a4f3f74c2 100644
--- a/diesel/src/pg/expression/helper_types.rs
+++ b/diesel/src/pg/expression/helper_types.rs
@@ -1,7 +1,7 @@
 use crate::dsl::{AsExpr, AsExprOf, SqlTypeOf};
 use crate::expression::grouped::Grouped;
 use crate::pg::types::sql_types::Array;
-use crate::sql_types::{Inet, Integer, Jsonb, VarChar};
+use crate::sql_types::{Binary, Inet, Integer, Jsonb, VarChar};
 
 /// The return type of [`lhs.ilike(rhs)`](super::expression_methods::PgTextExpressionMethods::ilike)
 #[cfg(feature = "postgres_backend")]
@@ -170,3 +170,17 @@ pub type RetrieveByPathAsTextJson<Lhs, Rhs> =
 #[cfg(feature = "postgres_backend")]
 pub type RemoveByPathFromJsonb<Lhs, Rhs> =
     Grouped<super::operators::RemoveByPathFromJsonb<Lhs, AsExprOf<Rhs, Array<VarChar>>>>;
+
+/// The return type of [`lhs.remove_by_path(rhs)`](super::expression_methods::PgBinaryExpressionMethods::concat)
+#[cfg(feature = "postgres_backend")]
+pub type ConcatBinary<Lhs, Rhs> =
+    Grouped<super::operators::ConcatBinary<Lhs, AsExprOf<Rhs, Binary>>>;
+
+/// The return type of [`lhs.remove_by_path(rhs)`](super::expression_methods::PgBinaryExpressionMethods::like)
+#[cfg(feature = "postgres_backend")]
+pub type LikeBinary<Lhs, Rhs> = Grouped<super::operators::LikeBinary<Lhs, AsExprOf<Rhs, Binary>>>;
+
+/// The return type of [`lhs.remove_by_path(rhs)`](super::expression_methods::PgBinaryExpressionMethods::not_like)
+#[cfg(feature = "postgres_backend")]
+pub type NotLikeBinary<Lhs, Rhs> =
+    Grouped<super::operators::NotLikeBinary<Lhs, AsExprOf<Rhs, Binary>>>;
diff --git a/diesel/src/pg/expression/operators.rs b/diesel/src/pg/expression/operators.rs
index 83db89d46eb1..ea99bf376ecf 100644
--- a/diesel/src/pg/expression/operators.rs
+++ b/diesel/src/pg/expression/operators.rs
@@ -5,7 +5,7 @@ use crate::pg::Pg;
 use crate::query_builder::update_statement::changeset::AssignmentTarget;
 use crate::query_builder::{AstPass, QueryFragment, QueryId};
 use crate::sql_types::{
-    Array, Bigint, Bool, DieselNumericOps, Inet, Integer, Jsonb, SqlType, Text,
+    Array, Bigint, Binary, Bool, DieselNumericOps, Inet, Integer, Jsonb, SqlType, Text,
 };
 use crate::{Column, QueryResult};
 
@@ -49,6 +49,9 @@ __diesel_infix_operator!(
 );
 infix_operator!(RetrieveByPathAsTextJson, " #>> ", Text, backend: Pg);
 infix_operator!(RemoveByPathFromJsonb, " #-", Jsonb, backend: Pg);
+infix_operator!(ConcatBinary, " || ", Binary, backend: Pg);
+infix_operator!(LikeBinary, " LIKE ", backend: Pg);
+infix_operator!(NotLikeBinary, " NOT LIKE ", backend: Pg);
 
 #[derive(Debug, Clone, Copy, QueryId, DieselNumericOps, ValidGrouping)]
 #[doc(hidden)]
diff --git a/diesel/src/pg/metadata_lookup.rs b/diesel/src/pg/metadata_lookup.rs
index 4f9a9d95edf2..8165bb125acd 100644
--- a/diesel/src/pg/metadata_lookup.rs
+++ b/diesel/src/pg/metadata_lookup.rs
@@ -9,6 +9,7 @@
 
 use super::backend::{FailedToLookupTypeError, InnerPgTypeMetadata};
 use super::{Pg, PgTypeMetadata};
+use crate::connection::{DefaultLoadingMode, LoadConnection};
 use crate::prelude::*;
 
 use std::borrow::Cow;
@@ -31,7 +32,7 @@ pub trait PgMetadataLookup {
 
 impl<T> PgMetadataLookup for T
 where
-    T: Connection<Backend = Pg> + GetPgMetadataCache,
+    T: Connection<Backend = Pg> + GetPgMetadataCache + LoadConnection<DefaultLoadingMode>,
 {
     fn lookup_type(&mut self, type_name: &str, schema: Option<&str>) -> PgTypeMetadata {
         let cache_key = PgMetadataCacheKey {
@@ -75,7 +76,7 @@ pub trait GetPgMetadataCache {
     fn get_metadata_cache(&mut self) -> &mut PgMetadataCache;
 }
 
-fn lookup_type<T: Connection<Backend = Pg>>(
+fn lookup_type<T: Connection<Backend = Pg> + LoadConnection<DefaultLoadingMode>>(
     cache_key: &PgMetadataCacheKey<'_>,
     conn: &mut T,
 ) -> QueryResult<InnerPgTypeMetadata> {
diff --git a/diesel/src/pg/mod.rs b/diesel/src/pg/mod.rs
index 3c9b0b5b7976..0c1f872dfc32 100644
--- a/diesel/src/pg/mod.rs
+++ b/diesel/src/pg/mod.rs
@@ -18,7 +18,7 @@ mod value;
 
 pub use self::backend::{Pg, PgTypeMetadata};
 #[cfg(feature = "postgres")]
-pub use self::connection::PgConnection;
+pub use self::connection::{PgConnection, PgRowByRowLoadingMode};
 #[doc(inline)]
 pub use self::metadata_lookup::PgMetadataLookup;
 #[doc(inline)]
diff --git a/diesel/src/pg/query_builder/distinct_on.rs b/diesel/src/pg/query_builder/distinct_on.rs
index cab64bec9c99..06bf8ffe744a 100644
--- a/diesel/src/pg/query_builder/distinct_on.rs
+++ b/diesel/src/pg/query_builder/distinct_on.rs
@@ -23,6 +23,33 @@ where
     T::SqlType: SingleValue,
 {
 }
+impl<T> ValidOrderingForDistinct<DistinctOnClause<T>> for OrderClause<crate::helper_types::Desc<T>>
+where
+    T: Expression,
+    T::SqlType: SingleValue,
+{
+}
+impl<T> ValidOrderingForDistinct<DistinctOnClause<T>> for OrderClause<crate::helper_types::Asc<T>>
+where
+    T: Expression,
+    T::SqlType: SingleValue,
+{
+}
+
+impl<T> ValidOrderingForDistinct<DistinctOnClause<T>>
+    for OrderClause<(crate::helper_types::Desc<T>,)>
+where
+    T: Expression,
+    T::SqlType: SingleValue,
+{
+}
+impl<T> ValidOrderingForDistinct<DistinctOnClause<T>>
+    for OrderClause<(crate::helper_types::Asc<T>,)>
+where
+    T: Expression,
+    T::SqlType: SingleValue,
+{
+}
 
 impl<T> QueryFragment<Pg> for DistinctOnClause<T>
 where
diff --git a/diesel/src/pg/query_builder/mod.rs b/diesel/src/pg/query_builder/mod.rs
index 0d088630e051..0889fe6283f7 100644
--- a/diesel/src/pg/query_builder/mod.rs
+++ b/diesel/src/pg/query_builder/mod.rs
@@ -55,7 +55,7 @@ impl QueryBuilder<Pg> for PgQueryBuilder {
 
 #[test]
 fn check_sql_query_increments_bind_count() {
-    use crate::query_builder::{AstPass, QueryFragment};
+    use crate::query_builder::{AstPass, AstPassToSqlOptions, QueryFragment};
     use crate::sql_types::*;
 
     let query = crate::sql_query("SELECT $1, $2, $3")
@@ -66,7 +66,8 @@ fn check_sql_query_increments_bind_count() {
     let mut query_builder = PgQueryBuilder::default();
 
     {
-        let ast_pass = AstPass::<crate::pg::Pg>::to_sql(&mut query_builder, &Pg);
+        let mut options = AstPassToSqlOptions::default();
+        let ast_pass = AstPass::<crate::pg::Pg>::to_sql(&mut query_builder, &mut options, &Pg);
 
         query.walk_ast(ast_pass).unwrap();
     }
diff --git a/diesel/src/pg/transaction.rs b/diesel/src/pg/transaction.rs
index 41110cd4b8a8..d679416484f4 100644
--- a/diesel/src/pg/transaction.rs
+++ b/diesel/src/pg/transaction.rs
@@ -1,6 +1,5 @@
 #![allow(dead_code)]
 use crate::backend::Backend;
-use crate::connection::commit_error_processor::CommitErrorProcessor;
 use crate::connection::{AnsiTransactionManager, TransactionManager};
 use crate::pg::Pg;
 use crate::prelude::*;
@@ -28,7 +27,7 @@ pub struct TransactionBuilder<'a, C> {
 
 impl<'a, C> TransactionBuilder<'a, C>
 where
-    C: Connection<Backend = Pg, TransactionManager = AnsiTransactionManager> + CommitErrorProcessor,
+    C: Connection<Backend = Pg, TransactionManager = AnsiTransactionManager>,
 {
     pub(crate) fn new(connection: &'a mut C) -> Self {
         Self {
@@ -269,21 +268,16 @@ where
     /// the closure returns `Ok(_)`, it will be rolled back if it returns `Err(_)`.
     /// For both cases the original result value will be returned from this function.
     ///
-    /// If the transaction fails to commit due to a `SerializationFailure` or a
-    /// `ReadOnlyTransaction` a rollback will be attempted. In this case a
-    /// [`Error::CommitTransactionFailed`](crate::result::Error::CommitTransactionFailed)
-    /// error is returned, which contains details about the original error and
-    /// the success of the rollback attempt.
-    /// If the rollback failed the connection should be considered broken
+    /// If the transaction fails to commit and requires a rollback according to Postgres,
+    /// (e.g. serialization failure) a rollback will be attempted.
+    /// If the rollback fails, the error will be returned in a
+    /// [`Error::RollbackErrorOnCommit`](crate::result::Error::RollbackErrorOnCommit),
+    /// from which you will be able to extract both the original commit error and
+    /// the rollback error.
+    /// In addition, the connection will be considered broken
     /// as it contains a uncommitted unabortable open transaction. Any further
     /// interaction with the transaction system will result in an returned error
-    /// in this cases.
-    ///
-    /// If the closure returns an `Err(_)` and the rollback fails the function
-    /// will return a [`Error::RollbackError`](crate::result::Error::RollbackError)
-    /// wrapping the error generated by the rollback operation instead.
-    /// In this case the connection should be considered broken as it contains
-    /// an unabortable open transaction.
+    /// in this case.
     pub fn run<T, E, F>(&mut self, f: F) -> Result<T, E>
     where
         F: FnOnce(&mut C) -> Result<T, E>,
@@ -299,10 +293,16 @@ where
                 AnsiTransactionManager::commit_transaction(&mut *self.connection)?;
                 Ok(value)
             }
-            Err(e) => {
-                AnsiTransactionManager::rollback_transaction(&mut *self.connection)
-                    .map_err(|e| Error::RollbackError(Box::new(e)))?;
-                Err(e)
+            Err(user_error) => {
+                match AnsiTransactionManager::rollback_transaction(&mut *self.connection) {
+                    Ok(()) => Err(user_error),
+                    Err(Error::BrokenTransactionManager) => {
+                        // In this case we are probably more interested by the
+                        // original error, which likely caused this
+                        Err(user_error)
+                    }
+                    Err(rollback_error) => Err(rollback_error.into()),
+                }
             }
         }
     }
diff --git a/diesel/src/pg/types/array.rs b/diesel/src/pg/types/array.rs
index 948560240df0..e80eb3216810 100644
--- a/diesel/src/pg/types/array.rs
+++ b/diesel/src/pg/types/array.rs
@@ -64,6 +64,9 @@ use crate::expression::AsExpression;
 macro_rules! array_as_expression {
     ($ty:ty, $sql_type:ty) => {
         #[cfg(feature = "postgres_backend")]
+        // this simplifies the macro implemntation
+        // as some macro calls use this lifetime
+        #[allow(clippy::extra_unused_lifetimes)]
         impl<'a, 'b, ST: 'static, T> AsExpression<$sql_type> for $ty {
             type Expression = Bound<$sql_type, Self>;
 
diff --git a/diesel/src/pg/types/date_and_time/std_time.rs b/diesel/src/pg/types/date_and_time/std_time.rs
index bd1880142da7..a25ec6c5b154 100644
--- a/diesel/src/pg/types/date_and_time/std_time.rs
+++ b/diesel/src/pg/types/date_and_time/std_time.rs
@@ -31,7 +31,7 @@ impl FromSql<sql_types::Timestamp, Pg> for SystemTime {
     fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
         let usecs_passed = <i64 as FromSql<sql_types::BigInt, Pg>>::from_sql(bytes)?;
         let before_epoch = usecs_passed < 0;
-        let time_passed = usecs_to_duration(usecs_passed.abs() as u64);
+        let time_passed = usecs_to_duration(usecs_passed.unsigned_abs());
 
         if before_epoch {
             Ok(pg_epoch() - time_passed)
diff --git a/diesel/src/pg/types/ipnet_address.rs b/diesel/src/pg/types/ipnet_address.rs
new file mode 100644
index 000000000000..10a5e6b8c84d
--- /dev/null
+++ b/diesel/src/pg/types/ipnet_address.rs
@@ -0,0 +1,271 @@
+extern crate libc;
+
+use ipnet::{IpNet, Ipv4Net, Ipv6Net};
+use std::io::prelude::*;
+use std::net::{Ipv4Addr, Ipv6Addr};
+
+use crate::deserialize::{self, FromSql, FromSqlRow};
+use crate::pg::{Pg, PgValue};
+#[cfg(test)]
+use crate::query_builder::bind_collector::ByteWrapper;
+use crate::serialize::{self, IsNull, Output, ToSql};
+use crate::sql_types::{Cidr, Inet};
+
+#[cfg(windows)]
+const AF_INET: u8 = 2;
+// Maybe not used, but defining to follow Rust's libstd/net/sys
+#[cfg(target_os = "redox")]
+const AF_INET: u8 = 1;
+#[cfg(not(any(windows, target_os = "redox")))]
+const AF_INET: u8 = libc::AF_INET as u8;
+
+const PGSQL_AF_INET: u8 = AF_INET;
+const PGSQL_AF_INET6: u8 = AF_INET + 1;
+
+#[allow(dead_code)]
+mod foreign_derives {
+    use super::*;
+    use crate::expression::AsExpression;
+
+    #[derive(AsExpression, FromSqlRow)]
+    #[diesel(foreign_derive)]
+    #[diesel(sql_type = Inet)]
+    #[diesel(sql_type = Cidr)]
+    struct IpNetworkProxy(IpNet);
+}
+
+macro_rules! err {
+    () => {
+        Err("invalid network address format".into())
+    };
+    ($msg:expr) => {
+        Err(format!("invalid network address format. {}", $msg).into())
+    };
+}
+
+macro_rules! assert_or_error {
+    ($cond:expr) => {
+        if !$cond {
+            return err!();
+        }
+    };
+
+    ($cond:expr, $msg:expr) => {
+        if !$cond {
+            return err!($msg);
+        }
+    };
+}
+
+macro_rules! impl_Sql {
+    ($ty: ty, $net_type: expr) => {
+        #[cfg(all(feature = "postgres_backend", feature = "ipnet-address"))]
+        impl FromSql<$ty, Pg> for IpNet {
+            fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
+                // https://github.com/postgres/postgres/blob/55c3391d1e6a201b5b891781d21fe682a8c64fe6/src/include/utils/inet.h#L23-L28
+                let bytes = value.as_bytes();
+                assert_or_error!(4 <= bytes.len(), "input is too short.");
+                let af = bytes[0];
+                let prefix = bytes[1];
+                let net_type = bytes[2];
+                let len = bytes[3];
+                assert_or_error!(
+                    net_type == $net_type,
+                    format!("returned type isn't a {}", stringify!($ty))
+                );
+                if af == PGSQL_AF_INET {
+                    assert_or_error!(bytes.len() == 8);
+                    assert_or_error!(len == 4, "the data isn't the size of ipv4");
+                    let b = &bytes[4..];
+                    let addr = Ipv4Addr::new(b[0], b[1], b[2], b[3]);
+                    let inet = Ipv4Net::new(addr, prefix)?;
+                    Ok(IpNet::V4(inet))
+                } else if af == PGSQL_AF_INET6 {
+                    assert_or_error!(bytes.len() == 20);
+                    assert_or_error!(len == 16, "the data isn't the size of ipv6");
+                    let b = &bytes[4..];
+                    let addr = Ipv6Addr::from([
+                        b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11],
+                        b[12], b[13], b[14], b[15],
+                    ]);
+                    let inet = Ipv6Net::new(addr, prefix)?;
+                    Ok(IpNet::V6(inet))
+                } else {
+                    err!()
+                }
+            }
+        }
+
+        #[cfg(all(feature = "postgres_backend", feature = "ipnet-address"))]
+        impl ToSql<$ty, Pg> for IpNet {
+            fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
+                let net_type = $net_type;
+                match *self {
+                    IpNet::V4(ref net) => {
+                        let mut data = [0u8; 8];
+                        let af = PGSQL_AF_INET;
+                        let prefix = net.prefix_len();
+                        let len: u8 = 4;
+                        let addr = net.network().octets();
+                        data[0] = af;
+                        data[1] = prefix;
+                        data[2] = net_type;
+                        data[3] = len;
+                        data[4..].copy_from_slice(&addr);
+                        out.write_all(&data).map(|_| IsNull::No).map_err(Into::into)
+                    }
+                    IpNet::V6(ref net) => {
+                        let mut data = [0u8; 20];
+                        let af = PGSQL_AF_INET6;
+                        let prefix = net.prefix_len();
+                        let len: u8 = 16;
+                        let addr = net.network().octets();
+                        data[0] = af;
+                        data[1] = prefix;
+                        data[2] = net_type;
+                        data[3] = len;
+                        data[4..].copy_from_slice(&addr);
+                        out.write_all(&data).map(|_| IsNull::No).map_err(Into::into)
+                    }
+                }
+            }
+        }
+    };
+}
+
+impl_Sql!(Inet, 0);
+impl_Sql!(Cidr, 1);
+
+#[test]
+fn v4address_to_sql() {
+    macro_rules! test_to_sql {
+        ($ty:ty, $net_type:expr) => {
+            let mut buffer = Vec::new();
+            {
+                let mut bytes = Output::test(ByteWrapper(&mut buffer));
+                let test_address =
+                    IpNet::V4(Ipv4Net::new(Ipv4Addr::new(127, 0, 0, 1), 32).unwrap());
+                ToSql::<$ty, Pg>::to_sql(&test_address, &mut bytes).unwrap();
+            }
+            assert_eq!(buffer, vec![PGSQL_AF_INET, 32, $net_type, 4, 127, 0, 0, 1]);
+        };
+    }
+
+    test_to_sql!(Inet, 0);
+    test_to_sql!(Cidr, 1);
+}
+
+#[test]
+fn some_v4address_from_sql() {
+    macro_rules! test_some_address_from_sql {
+        ($ty:tt) => {
+            let input_address = IpNet::V4(Ipv4Net::new(Ipv4Addr::new(127, 0, 0, 1), 32).unwrap());
+            let mut buffer = Vec::new();
+            {
+                let mut bytes = Output::test(ByteWrapper(&mut buffer));
+                ToSql::<$ty, Pg>::to_sql(&input_address, &mut bytes).unwrap();
+            }
+            let output_address = FromSql::<$ty, Pg>::from_sql(PgValue::for_test(&buffer)).unwrap();
+            assert_eq!(input_address, output_address);
+        };
+    }
+
+    test_some_address_from_sql!(Cidr);
+    test_some_address_from_sql!(Inet);
+}
+
+#[test]
+fn v6address_to_sql() {
+    macro_rules! test_to_sql {
+        ($ty:ty, $net_type:expr) => {
+            let mut buffer = Vec::new();
+            {
+                let mut bytes = Output::test(ByteWrapper(&mut buffer));
+                let test_address =
+                    IpNet::V6(Ipv6Net::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 64).unwrap());
+                ToSql::<$ty, Pg>::to_sql(&test_address, &mut bytes).unwrap();
+            }
+            assert_eq!(
+                buffer,
+                vec![
+                    PGSQL_AF_INET6,
+                    64,
+                    $net_type,
+                    16,
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    1,
+                ]
+            );
+        };
+    }
+
+    test_to_sql!(Inet, 0);
+    test_to_sql!(Cidr, 1);
+}
+
+#[test]
+fn some_v6address_from_sql() {
+    macro_rules! test_some_address_from_sql {
+        ($ty:tt) => {
+            let input_address =
+                IpNet::V6(Ipv6Net::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 64).unwrap());
+            let mut buffer = Vec::new();
+            {
+                let mut bytes = Output::test(ByteWrapper(&mut buffer));
+                ToSql::<$ty, Pg>::to_sql(&input_address, &mut bytes).unwrap();
+            }
+            let output_address = FromSql::<$ty, Pg>::from_sql(PgValue::for_test(&buffer)).unwrap();
+            assert_eq!(input_address, output_address);
+        };
+    }
+
+    test_some_address_from_sql!(Inet);
+    test_some_address_from_sql!(Cidr);
+}
+
+#[test]
+fn bad_address_from_sql() {
+    macro_rules! bad_address_from_sql {
+        ($ty:tt) => {
+            let address: Result<IpNet, _> =
+                FromSql::<$ty, Pg>::from_sql(PgValue::for_test(&[7, PGSQL_AF_INET, 0]));
+            assert_eq!(
+                address.unwrap_err().to_string(),
+                "invalid network address format. input is too short."
+            );
+        };
+    }
+
+    bad_address_from_sql!(Inet);
+    bad_address_from_sql!(Cidr);
+}
+
+#[test]
+fn no_address_from_sql() {
+    macro_rules! test_no_address_from_sql {
+        ($ty:ty) => {
+            let address: Result<IpNet, _> = FromSql::<$ty, Pg>::from_nullable_sql(None);
+            assert_eq!(
+                address.unwrap_err().to_string(),
+                "Unexpected null for non-null column"
+            );
+        };
+    }
+
+    test_no_address_from_sql!(Inet);
+    test_no_address_from_sql!(Cidr);
+}
diff --git a/diesel/src/pg/types/mod.rs b/diesel/src/pg/types/mod.rs
index 2935795d633f..4e0632e0487e 100644
--- a/diesel/src/pg/types/mod.rs
+++ b/diesel/src/pg/types/mod.rs
@@ -6,6 +6,8 @@ pub(in crate::pg) mod date_and_time;
 #[doc(hidden)]
 pub(in crate::pg) mod floats;
 mod integers;
+#[cfg(feature = "ipnet-address")]
+mod ipnet_address;
 #[cfg(feature = "serde_json")]
 mod json;
 mod mac_addr;
@@ -86,8 +88,7 @@ pub mod sql_types {
     /// The [`Array`] SQL type.
     ///
     /// This wraps another type to represent a SQL array of that type.
-    /// Multidimensional arrays are not supported,
-    /// nor are arrays containing null.
+    /// Multidimensional arrays are not supported.
     ///
     /// ### [`ToSql`] impls
     ///
@@ -405,23 +406,24 @@ pub mod sql_types {
     /// Alias for `MacAddr` to be able to use it with `infer_schema`.
     pub type Macaddr = MacAddr;
 
-    /// The [`INET`](https://www.postgresql.org/docs/current/static/datatype-net-types.html) SQL type. This type can only be used with `feature = "network-address"`
+    /// The [`INET`](https://www.postgresql.org/docs/current/static/datatype-net-types.html) SQL type. This type can only be used with `feature = "network-address"` or `feature = "ipnet-address"`.
     ///
     /// ### [`ToSql`] impls
     ///
-    /// - [`ipnetwork::IpNetwork`][IpNetwork]
+    #[cfg_attr(feature = "ipnetwork", doc = " - [`ipnetwork::IpNetwork`][IpNetwork]")]
+    #[cfg_attr(feature = "ipnet", doc = " - [`ipnet::IpNet`][IpNet]")]
+    #[cfg_attr(not(any(feature = "ipnetwork", feature = "ipnet")), doc = "N/A")]
     ///
     /// ### [`FromSql`] impls
     ///
-    /// - [`ipnetwork::IpNetwork`][IpNetwork]
+    #[cfg_attr(feature = "ipnetwork", doc = " - [`ipnetwork::IpNetwork`][IpNetwork]")]
+    #[cfg_attr(feature = "ipnet", doc = " - [`ipnet::IpNet`][IpNet]")]
+    #[cfg_attr(not(any(feature = "ipnetwork", feature = "ipnet")), doc = "N/A")]
     ///
     /// [`ToSql`]: crate::serialize::ToSql
     /// [`FromSql`]: crate::deserialize::FromSql
     #[cfg_attr(feature = "ipnetwork", doc = " [IpNetwork]: ipnetwork::IpNetwork")]
-    #[cfg_attr(
-        not(feature = "ipnetwork"),
-        doc = " [IpNetwork]: https://docs.rs/ipnetwork/*/ipnetwork/enum.IpNetwork.html"
-    )]
+    #[cfg_attr(feature = "ipnet", doc = " [IpNet]: ipnet::IpNet")]
     ///
     /// # Examples
     ///
@@ -435,9 +437,8 @@ pub mod sql_types {
     ///     }
     /// }
     ///
-    /// # #[cfg(feature = "network-address")]
+    /// # #[cfg(any(feature = "network-address", feature = "ipnet-address"))]
     /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
-    /// use ipnetwork::IpNetwork;
     ///
     /// #     use diesel::insert_into;
     /// #     use self::clients::dsl::*;
@@ -446,7 +447,8 @@ pub mod sql_types {
     /// #         id SERIAL PRIMARY KEY,
     /// #         ip_address INET NOT NULL
     /// #     )").execute(connection)?;
-    /// let addr = "10.1.9.32/32".parse::<IpNetwork>()?;
+    /// // Parsing "ipnet::IpNet" would also work.
+    /// let addr = "10.1.9.32/32".parse::<ipnetwork::IpNetwork>()?;
     /// let inserted_address = insert_into(clients)
     ///     .values(ip_address.eq(&addr))
     ///     .returning(ip_address)
@@ -455,7 +457,7 @@ pub mod sql_types {
     /// #     Ok(())
     /// # }
     /// #
-    /// # #[cfg(not(feature = "network-address"))]
+    /// # #[cfg(not(any(feature = "network-address", feature = "ipnet-address")))]
     /// # fn main() {}
     /// ```
     #[cfg(feature = "postgres_backend")]
@@ -463,23 +465,24 @@ pub mod sql_types {
     #[diesel(postgres_type(oid = 869, array_oid = 1041))]
     pub struct Inet;
 
-    /// The [`CIDR`](https://www.postgresql.org/docs/postgresql/static/datatype-net-types.html) SQL type. This type can only be used with `feature = "network-address"`
+    /// The [`CIDR`](https://www.postgresql.org/docs/postgresql/static/datatype-net-types.html) SQL type. This type can only be used with `feature = "network-address"` or `feature = "ipnet-address"`.
     ///
     /// ### [`ToSql`] impls
     ///
-    /// - [`ipnetwork::IpNetwork`][IpNetwork]
+    #[cfg_attr(feature = "ipnetwork", doc = " - [`ipnetwork::IpNetwork`][IpNetwork]")]
+    #[cfg_attr(feature = "ipnet", doc = " - [`ipnet::IpNet`][IpNet]")]
+    #[cfg_attr(not(any(feature = "ipnetwork", feature = "ipnet")), doc = "N/A")]
     ///
     /// ### [`FromSql`] impls
     ///
-    /// - [`ipnetwork::IpNetwork`][IpNetwork]
+    #[cfg_attr(feature = "ipnetwork", doc = " - [`ipnetwork::IpNetwork`][IpNetwork]")]
+    #[cfg_attr(feature = "ipnet", doc = " - [`ipnet::IpNet`][IpNet]")]
+    #[cfg_attr(not(any(feature = "ipnetwork", feature = "ipnet")), doc = "N/A")]
     ///
     /// [`ToSql`]: crate::serialize::ToSql
     /// [`FromSql`]: crate::deserialize::FromSql
     #[cfg_attr(feature = "ipnetwork", doc = " [IpNetwork]: ipnetwork::IpNetwork")]
-    #[cfg_attr(
-        not(feature = "ipnetwork"),
-        doc = " [IpNetwork]: https://docs.rs/ipnetwork/*/ipnetwork/enum.IpNetwork.html"
-    )]
+    #[cfg_attr(feature = "ipnet", doc = " [IpNet]: ipnet::IpNet")]
     ///
     /// # Examples
     ///
@@ -493,9 +496,8 @@ pub mod sql_types {
     ///     }
     /// }
     ///
-    /// # #[cfg(feature = "network-address")]
+    /// # #[cfg(any(feature = "network-address", feature = "ipnet-address"))]
     /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
-    /// use ipnetwork::IpNetwork;
     ///
     /// #     use diesel::insert_into;
     /// #     use self::clients::dsl::*;
@@ -504,7 +506,8 @@ pub mod sql_types {
     /// #         id SERIAL PRIMARY KEY,
     /// #         ip_address CIDR NOT NULL
     /// #     )").execute(connection)?;
-    /// let addr = "10.1.9.32/32".parse::<IpNetwork>()?;
+    /// // Parsing "ipnet::IpNet" would also work.
+    /// let addr = "10.1.9.32/32".parse::<ipnetwork::IpNetwork>()?;
     /// let inserted_addr = insert_into(clients)
     ///     .values(ip_address.eq(&addr))
     ///     .returning(ip_address)
@@ -512,7 +515,7 @@ pub mod sql_types {
     /// assert_eq!(addr, inserted_addr);
     /// #     Ok(())
     /// # }
-    /// # #[cfg(not(feature = "network-address"))]
+    /// # #[cfg(not(any(feature = "network-address", feature = "ipnet-address")))]
     /// # fn main() {}
     /// ```
     #[cfg(feature = "postgres_backend")]
diff --git a/diesel/src/query_builder/ast_pass.rs b/diesel/src/query_builder/ast_pass.rs
index 1d45c61bb28b..a67fb350d0ec 100644
--- a/diesel/src/query_builder/ast_pass.rs
+++ b/diesel/src/query_builder/ast_pass.rs
@@ -38,9 +38,13 @@ where
     DB: Backend,
     'b: 'a,
 {
-    pub(crate) fn to_sql(query_builder: &'a mut DB::QueryBuilder, backend: &'b DB) -> Self {
+    pub(crate) fn to_sql(
+        query_builder: &'a mut DB::QueryBuilder,
+        options: &'a mut AstPassToSqlOptions,
+        backend: &'b DB,
+    ) -> Self {
         AstPass {
-            internals: AstPassInternals::ToSql(query_builder),
+            internals: AstPassInternals::ToSql(query_builder, options),
             backend,
         }
     }
@@ -84,6 +88,13 @@ where
         }
     }
 
+    #[cfg(feature = "sqlite")]
+    pub(crate) fn skip_from(&mut self, value: bool) {
+        if let AstPassInternals::ToSql(_, ref mut options) = self.internals {
+            options.skip_from = value
+        }
+    }
+
     /// Call this method whenever you pass an instance of `AstPass` by value.
     ///
     /// Effectively copies `self`, with a narrower lifetime. When passing a
@@ -95,7 +106,9 @@ where
     /// implicitly if you were passing a mutable reference
     pub fn reborrow(&'_ mut self) -> AstPass<'_, 'b, DB> {
         let internals = match self.internals {
-            AstPassInternals::ToSql(ref mut builder) => AstPassInternals::ToSql(&mut **builder),
+            AstPassInternals::ToSql(ref mut builder, ref mut options) => {
+                AstPassInternals::ToSql(&mut **builder, &mut **options)
+            }
             AstPassInternals::CollectBinds {
                 ref mut collector,
                 ref mut metadata_lookup,
@@ -167,7 +180,7 @@ where
     /// ```
     pub fn push_sql(&mut self, sql: &str) {
         match self.internals {
-            AstPassInternals::ToSql(ref mut builder) => builder.push_sql(sql),
+            AstPassInternals::ToSql(ref mut builder, _) => builder.push_sql(sql),
             AstPassInternals::IsNoop(ref mut result) => **result = false,
             _ => {}
         }
@@ -179,7 +192,7 @@ where
     /// the query is being constructed for.
     pub fn push_identifier(&mut self, identifier: &str) -> QueryResult<()> {
         match self.internals {
-            AstPassInternals::ToSql(ref mut builder) => builder.push_identifier(identifier)?,
+            AstPassInternals::ToSql(ref mut builder, _) => builder.push_identifier(identifier)?,
             AstPassInternals::IsNoop(ref mut result) => **result = false,
             _ => {}
         }
@@ -197,7 +210,7 @@ where
         U: ToSql<T, DB>,
     {
         match self.internals {
-            AstPassInternals::ToSql(ref mut out) => out.push_bind_param(),
+            AstPassInternals::ToSql(ref mut out, _) => out.push_bind_param(),
             AstPassInternals::CollectBinds {
                 ref mut collector,
                 ref mut metadata_lookup,
@@ -220,7 +233,7 @@ where
             AstPassInternals::CollectBinds { .. } | AstPassInternals::DebugBinds(..) => {
                 self.push_bind_param(bind)?
             }
-            AstPassInternals::ToSql(ref mut out) => {
+            AstPassInternals::ToSql(ref mut out, _) => {
                 out.push_bind_param_value_only();
             }
             _ => {}
@@ -240,6 +253,23 @@ where
     pub fn backend(&self) -> &DB {
         self.backend
     }
+
+    /// Get if the query should be rendered with from clauses or not
+    #[cfg_attr(
+        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
+        doc(hidden)
+    )] // This is used by the `__diesel_column` macro
+    #[cfg_attr(
+        doc_cfg,
+        doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
+    )]
+    pub fn should_skip_from(&self) -> bool {
+        if let AstPassInternals::ToSql(_, ref options) = self.internals {
+            options.skip_from
+        } else {
+            false
+        }
+    }
 }
 
 #[allow(missing_debug_implementations)]
@@ -255,7 +285,7 @@ where
     DB::MetadataLookup: 'a,
     'b: 'a,
 {
-    ToSql(&'a mut DB::QueryBuilder),
+    ToSql(&'a mut DB::QueryBuilder, &'a mut AstPassToSqlOptions),
     CollectBinds {
         collector: &'a mut <DB as HasBindCollector<'b>>::BindCollector,
         metadata_lookup: &'a mut DB::MetadataLookup,
@@ -264,3 +294,15 @@ where
     DebugBinds(&'a mut Vec<&'b dyn fmt::Debug>),
     IsNoop(&'a mut bool),
 }
+
+#[diesel_derives::__diesel_public_if(
+    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+)]
+#[allow(missing_debug_implementations)]
+#[allow(missing_copy_implementations)]
+#[derive(Default)]
+/// This is used to pass down additional settings to the `AstPass`
+/// when rendering the sql string.
+pub(crate) struct AstPassToSqlOptions {
+    skip_from: bool,
+}
diff --git a/diesel/src/query_builder/combination_clause.rs b/diesel/src/query_builder/combination_clause.rs
index 5435bd395e37..23a7002e0a6c 100644
--- a/diesel/src/query_builder/combination_clause.rs
+++ b/diesel/src/query_builder/combination_clause.rs
@@ -26,8 +26,8 @@ where
 pub struct CombinationClause<Combinator, Rule, Source, Rhs> {
     combinator: Combinator,
     duplicate_rule: Rule,
-    source: Source,
-    rhs: RhsParenthesisWrapper<Rhs>,
+    source: ParenthesisWrapper<Source>,
+    rhs: ParenthesisWrapper<Rhs>,
 }
 
 impl<Combinator, Rule, Source, Rhs> CombinationClause<Combinator, Rule, Source, Rhs> {
@@ -41,8 +41,8 @@ impl<Combinator, Rule, Source, Rhs> CombinationClause<Combinator, Rule, Source,
         CombinationClause {
             combinator,
             duplicate_rule,
-            source,
-            rhs: RhsParenthesisWrapper(rhs),
+            source: ParenthesisWrapper(source),
+            rhs: ParenthesisWrapper(rhs),
         }
     }
 }
@@ -129,8 +129,8 @@ impl<Combinator, Rule, Source, Rhs, DB: Backend> QueryFragment<DB>
 where
     Combinator: QueryFragment<DB>,
     Rule: QueryFragment<DB>,
-    Source: QueryFragment<DB>,
-    RhsParenthesisWrapper<Rhs>: QueryFragment<DB>,
+    ParenthesisWrapper<Source>: QueryFragment<DB>,
+    ParenthesisWrapper<Rhs>: QueryFragment<DB>,
     DB: Backend + SupportsCombinationClause<Combinator, Rule> + DieselReserveSpecialization,
 {
     fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
@@ -215,7 +215,7 @@ pub trait SupportsCombinationClause<Combinator, Rule> {}
 
 #[derive(Debug, Copy, Clone, QueryId)]
 /// Wrapper used to wrap rhs sql in parenthesis when supported by backend
-pub struct RhsParenthesisWrapper<T>(T);
+pub struct ParenthesisWrapper<T>(T);
 
 #[cfg(feature = "postgres")]
 mod postgres {
@@ -224,7 +224,7 @@ mod postgres {
     use crate::query_builder::{AstPass, QueryFragment};
     use crate::QueryResult;
 
-    impl<T: QueryFragment<Pg>> QueryFragment<Pg> for RhsParenthesisWrapper<T> {
+    impl<T: QueryFragment<Pg>> QueryFragment<Pg> for ParenthesisWrapper<T> {
         fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Pg>) -> QueryResult<()> {
             out.push_sql("(");
             self.0.walk_ast(out.reborrow())?;
@@ -248,7 +248,7 @@ mod mysql {
     use crate::query_builder::{AstPass, QueryFragment};
     use crate::QueryResult;
 
-    impl<T: QueryFragment<Mysql>> QueryFragment<Mysql> for RhsParenthesisWrapper<T> {
+    impl<T: QueryFragment<Mysql>> QueryFragment<Mysql> for ParenthesisWrapper<T> {
         fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
             out.push_sql("(");
             self.0.walk_ast(out.reborrow())?;
@@ -268,9 +268,15 @@ mod sqlite {
     use crate::sqlite::Sqlite;
     use crate::QueryResult;
 
-    impl<T: QueryFragment<Sqlite>> QueryFragment<Sqlite> for RhsParenthesisWrapper<T> {
-        fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
-            self.0.walk_ast(out) // SQLite does not support parenthesis around Ths
+    impl<T: QueryFragment<Sqlite>> QueryFragment<Sqlite> for ParenthesisWrapper<T> {
+        fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
+            // SQLite does not support parenthesis around Ths
+            // we can emulate this by construct a fake outer
+            // SELECT * FROM (inner_query) statement
+            out.push_sql("SELECT * FROM (");
+            self.0.walk_ast(out.reborrow())?;
+            out.push_sql(")");
+            Ok(())
         }
     }
 
diff --git a/diesel/src/query_builder/functions.rs b/diesel/src/query_builder/functions.rs
index 153ef0b9e07a..5ef19cad96ab 100644
--- a/diesel/src/query_builder/functions.rs
+++ b/diesel/src/query_builder/functions.rs
@@ -588,8 +588,7 @@ pub fn replace_into<T: Table>(target: T) -> IncompleteReplaceStatement<T> {
 /// #     #[cfg(not(feature = "postgres"))]
 /// // Checkout the documentation of your database for the correct
 /// // bind placeholder
-/// let users = sql_query("SELECT * FROM users WHERE id > ? AND name <> ?")
-/// # ;
+/// let users = sql_query("SELECT * FROM users WHERE id > ? AND name <> ?");
 /// let users = users
 ///     .bind::<Integer, _>(1)
 ///     .bind::<Text, _>("Tess")
diff --git a/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs b/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs
index 23b9960c7bcc..0cc5d2811596 100644
--- a/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs
+++ b/diesel/src/query_builder/insert_statement/insert_with_default_for_sqlite.rs
@@ -357,7 +357,7 @@ macro_rules! tuple_impls {
     }
 
 macro_rules! impl_contains_defaultable_value {
-    (
+      (
         @build
         start_ts = [$($ST: ident,)*],
         ts = [$T1: ident,],
diff --git a/diesel/src/query_builder/mod.rs b/diesel/src/query_builder/mod.rs
index 7cbad028dff2..456e3fe279c3 100644
--- a/diesel/src/query_builder/mod.rs
+++ b/diesel/src/query_builder/mod.rs
@@ -26,7 +26,7 @@ pub(crate) mod locking_clause;
 pub(crate) mod nodes;
 pub(crate) mod offset_clause;
 pub(crate) mod order_clause;
-mod returning_clause;
+pub(crate) mod returning_clause;
 pub(crate) mod select_clause;
 pub(crate) mod select_statement;
 mod sql_query;
@@ -86,6 +86,12 @@ pub use self::insert_statement::DefaultValues;
 #[doc(inline)]
 pub use self::returning_clause::ReturningClause;
 
+#[doc(inline)]
+#[diesel_derives::__diesel_public_if(
+    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+)]
+pub(crate) use self::ast_pass::AstPassToSqlOptions;
+
 #[doc(inline)]
 #[diesel_derives::__diesel_public_if(
     feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
@@ -203,7 +209,8 @@ pub trait QueryFragment<DB: Backend, SP = self::private::NotSpecialized> {
         feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
     )]
     fn to_sql(&self, out: &mut DB::QueryBuilder, backend: &DB) -> QueryResult<()> {
-        self.walk_ast(AstPass::to_sql(out, backend))
+        let mut options = AstPassToSqlOptions::default();
+        self.walk_ast(AstPass::to_sql(out, &mut options, backend))
     }
 
     /// Serializes all bind parameters in this query.
@@ -333,10 +340,10 @@ pub trait AsQuery {
 }
 
 impl<T: Query> AsQuery for T {
-    type SqlType = <Self as Query>::SqlType;
-    type Query = Self;
+    type SqlType = <T as Query>::SqlType;
+    type Query = T;
 
-    fn as_query(self) -> Self::Query {
+    fn as_query(self) -> <T as AsQuery>::Query {
         self
     }
 }
diff --git a/diesel/src/query_builder/select_statement/dsl_impls.rs b/diesel/src/query_builder/select_statement/dsl_impls.rs
index 8353f1c4d150..b73338089da3 100644
--- a/diesel/src/query_builder/select_statement/dsl_impls.rs
+++ b/diesel/src/query_builder/select_statement/dsl_impls.rs
@@ -604,7 +604,7 @@ where
     }
 }
 
-impl<'a, F, S, D, W, O, LOf, G, H> SelectNullableDsl
+impl<F, S, D, W, O, LOf, G, H> SelectNullableDsl
     for SelectStatement<F, SelectClause<S>, D, W, O, LOf, G, H>
 {
     type Output = SelectStatement<F, SelectClause<Nullable<S>>, D, W, O, LOf, G, H>;
@@ -624,7 +624,7 @@ impl<'a, F, S, D, W, O, LOf, G, H> SelectNullableDsl
     }
 }
 
-impl<'a, F, D, W, O, LOf, G, H> SelectNullableDsl
+impl<F, D, W, O, LOf, G, H> SelectNullableDsl
     for SelectStatement<F, DefaultSelectClause<F>, D, W, O, LOf, G, H>
 where
     F: AsQuerySource,
diff --git a/diesel/src/query_dsl/load_dsl.rs b/diesel/src/query_dsl/load_dsl.rs
index a601beb671c3..046304b2fb6e 100644
--- a/diesel/src/query_dsl/load_dsl.rs
+++ b/diesel/src/query_dsl/load_dsl.rs
@@ -1,7 +1,7 @@
 use self::private::LoadIter;
 use super::RunQueryDsl;
 use crate::backend::Backend;
-use crate::connection::{Connection, ConnectionGatWorkaround};
+use crate::connection::{Connection, ConnectionGatWorkaround, DefaultLoadingMode, LoadConnection};
 use crate::deserialize::FromSqlRow;
 use crate::expression::QueryMetadata;
 use crate::query_builder::{AsQuery, QueryFragment, QueryId};
@@ -20,25 +20,29 @@ pub(crate) use self::private::{CompatibleType, LoadQueryGatWorkaround};
 /// to call `load` from generic code.
 ///
 /// [`RunQueryDsl`]: crate::RunQueryDsl
-pub trait LoadQuery<'query, Conn, U>: RunQueryDsl<Conn>
+pub trait LoadQuery<'query, Conn, U, B = DefaultLoadingMode>: RunQueryDsl<Conn>
 where
-    for<'a> Self: LoadQueryGatWorkaround<'a, 'query, Conn, U>,
+    for<'a> Self: LoadQueryGatWorkaround<'a, 'query, Conn, U, B>,
 {
     /// Load this query
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
     fn internal_load<'conn>(
         self,
         conn: &'conn mut Conn,
-    ) -> QueryResult<<Self as LoadQueryGatWorkaround<'conn, 'query, Conn, U>>::Ret>;
+    ) -> QueryResult<<Self as LoadQueryGatWorkaround<'conn, 'query, Conn, U, B>>::Ret>;
 }
 
 /// The return type of [`LoadQuery<C, U>::internal_load()`]
 ///
 /// Users should thread this type as `impl Iterator<Item = QueryResult<U>>`
-pub type LoadRet<'conn, 'query, Q, C, U> = <Q as LoadQueryGatWorkaround<'conn, 'query, C, U>>::Ret;
+pub type LoadRet<'conn, 'query, Q, C, U, B = DefaultLoadingMode> =
+    <Q as LoadQueryGatWorkaround<'conn, 'query, C, U, B>>::Ret;
 
-impl<'conn, 'query, Conn, T, U, DB> LoadQueryGatWorkaround<'conn, 'query, Conn, U> for T
+impl<'conn, 'query, Conn, T, U, DB, B> LoadQueryGatWorkaround<'conn, 'query, Conn, U, B> for T
 where
-    Conn: Connection<Backend = DB>,
+    Conn: Connection<Backend = DB> + ConnectionGatWorkaround<'conn, 'query, DB, B>,
     T: AsQuery + RunQueryDsl<Conn>,
     T::Query: QueryFragment<DB> + QueryId,
     T::SqlType: CompatibleType<U, DB>,
@@ -47,17 +51,16 @@ where
     <T::SqlType as CompatibleType<U, DB>>::SqlType: 'static,
 {
     type Ret = LoadIter<
-        'conn,
         U,
-        <Conn as ConnectionGatWorkaround<'conn, 'query, DB>>::Cursor,
+        <Conn as ConnectionGatWorkaround<'conn, 'query, DB, B>>::Cursor,
         <T::SqlType as CompatibleType<U, DB>>::SqlType,
         DB,
     >;
 }
 
-impl<'query, Conn, T, U, DB> LoadQuery<'query, Conn, U> for T
+impl<'query, Conn, T, U, DB, B> LoadQuery<'query, Conn, U, B> for T
 where
-    Conn: Connection<Backend = DB>,
+    Conn: Connection<Backend = DB> + LoadConnection<B>,
     T: AsQuery + RunQueryDsl<Conn>,
     T::Query: QueryFragment<DB> + QueryId + 'query,
     T::SqlType: CompatibleType<U, DB>,
@@ -68,7 +71,7 @@ where
     fn internal_load<'conn>(
         self,
         conn: &'conn mut Conn,
-    ) -> QueryResult<<Self as LoadQueryGatWorkaround<'conn, 'query, Conn, U>>::Ret> {
+    ) -> QueryResult<<Self as LoadQueryGatWorkaround<'conn, 'query, Conn, U, B>>::Ret> {
         Ok(LoadIter {
             cursor: conn.load(self.as_query())?,
             _marker: Default::default(),
@@ -90,13 +93,15 @@ pub trait ExecuteDsl<Conn: Connection<Backend = DB>, DB: Backend = <Conn as Conn
     fn execute(query: Self, conn: &mut Conn) -> QueryResult<usize>;
 }
 
+use crate::result::Error;
+
 impl<Conn, DB, T> ExecuteDsl<Conn, DB> for T
 where
     Conn: Connection<Backend = DB>,
     DB: Backend,
     T: QueryFragment<DB> + QueryId,
 {
-    fn execute(query: Self, conn: &mut Conn) -> QueryResult<usize> {
+    fn execute(query: T, conn: &mut Conn) -> Result<usize, Error> {
         conn.execute_returning_count(&query)
     }
 }
@@ -109,6 +114,7 @@ where
 // * LoadIter as it's an implementation detail
 mod private {
     use crate::backend::Backend;
+    use crate::connection::DefaultLoadingMode;
     use crate::deserialize::FromSqlRow;
     use crate::expression::select_by::SelectBy;
     use crate::expression::{Expression, TypedExpressionType};
@@ -119,17 +125,17 @@ mod private {
         feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
         cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")
     )]
-    pub trait LoadQueryGatWorkaround<'conn, 'query, Conn, U> {
+    pub trait LoadQueryGatWorkaround<'conn, 'query, Conn, U, B = DefaultLoadingMode> {
         type Ret: Iterator<Item = QueryResult<U>>;
     }
 
     #[allow(missing_debug_implementations)]
-    pub struct LoadIter<'a, U, C, ST, DB> {
+    pub struct LoadIter<U, C, ST, DB> {
         pub(super) cursor: C,
-        pub(super) _marker: std::marker::PhantomData<&'a (ST, U, DB)>,
+        pub(super) _marker: std::marker::PhantomData<(ST, U, DB)>,
     }
 
-    impl<'a, C, U, ST, DB, R> LoadIter<'a, U, C, ST, DB>
+    impl<'a, C, U, ST, DB, R> LoadIter<U, C, ST, DB>
     where
         DB: Backend,
         C: Iterator<Item = QueryResult<R>>,
@@ -146,7 +152,7 @@ mod private {
         }
     }
 
-    impl<'a, C, U, ST, DB, R> Iterator for LoadIter<'a, U, C, ST, DB>
+    impl<'a, C, U, ST, DB, R> Iterator for LoadIter<U, C, ST, DB>
     where
         DB: Backend,
         C: Iterator<Item = QueryResult<R>>,
@@ -182,7 +188,7 @@ mod private {
         }
     }
 
-    impl<'a, C, U, ST, DB, R> ExactSizeIterator for LoadIter<'a, U, C, ST, DB>
+    impl<'a, C, U, ST, DB, R> ExactSizeIterator for LoadIter<U, C, ST, DB>
     where
         DB: Backend,
         C: ExactSizeIterator + Iterator<Item = QueryResult<R>>,
@@ -195,8 +201,8 @@ mod private {
     }
 
     #[cfg_attr(
-        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
-        cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")
+        doc_cfg,
+        doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
     )]
     pub trait CompatibleType<U, DB> {
         type SqlType;
diff --git a/diesel/src/query_dsl/mod.rs b/diesel/src/query_dsl/mod.rs
index a61ed930aef8..f77187a501eb 100644
--- a/diesel/src/query_dsl/mod.rs
+++ b/diesel/src/query_dsl/mod.rs
@@ -331,10 +331,9 @@ pub trait QueryDsl: Sized {
     /// [`.on`]: JoinOnDsl::on()
     ///
     /// You can join to as many tables as you'd like in a query, with the
-    /// restriction that no table can appear in the query more than once. The reason
-    /// for this restriction is that one of the appearances would require aliasing,
-    /// and we do not currently have a fleshed out story for dealing with table
-    /// aliases.
+    /// restriction that no table can appear in the query more than once. For
+    /// tables that appear more than once in a single query the usage of [`alias!`](crate::alias!)
+    /// is required.
     ///
     /// You will also need to call [`allow_tables_to_appear_in_same_query!`].
     /// If you are using `diesel print-schema`, this will
@@ -350,8 +349,11 @@ pub trait QueryDsl: Sized {
     ///
     /// ```sql
     /// SELECT * FROM users
-    ///     INNER JOIN posts ON posts.user_id = users.id
-    ///     INNER JOIN comments ON comments.post_id = posts.id
+    ///     INNER JOIN (
+    ///         posts
+    ///         INNER JOIN comments ON comments.post_id = posts.id
+    ///     ) ON posts.user_id = users.id
+    ///
     /// ```
     ///
     /// While the second query would deserialize into `(User, Post, Comment)` and
@@ -363,6 +365,14 @@ pub trait QueryDsl: Sized {
     ///     INNER JOIN comments ON comments.user_id = users.id
     /// ```
     ///
+    /// The exact generated SQL may change in future diesel version as long as the
+    /// generated query continues to produce same results. The currently generated
+    /// SQL is referred as ["explicit join"](https://www.postgresql.org/docs/current/explicit-joins.html)
+    /// by the PostgreSQL documentation and may have implications on the chosen query plan
+    /// for large numbers of joins in the same query. Checkout the documentation of the
+    /// [`join_collapse_limit` paramater](https://www.postgresql.org/docs/current/runtime-config-query.html#GUC-JOIN-COLLAPSE-LIMIT)
+    /// to control this behaviour.
+    ///
     /// [associations]: crate::associations
     /// [`allow_tables_to_appear_in_same_query!`]: crate::allow_tables_to_appear_in_same_query!
     ///
@@ -1501,6 +1511,17 @@ pub trait RunQueryDsl<Conn>: Sized {
     ///
     /// When using the query builder, the return type can be
     /// a tuple of the values, or a struct which implements [`Queryable`].
+    /// This type is specified by the first generic type of this function.
+    ///
+    /// The second generic type paramater specifies the so called loading mode,
+    /// which describes how the connection implementation loads data from the database.
+    /// All connections should provide a implementaiton for
+    /// [`DefaultLoadingMode`](crate::connection::DefaultLoadingMode).
+    ///
+    /// They may provide additional modes. Checkout the documentation of the concrete
+    /// connection types for details. For connection implementations that provide
+    /// more than one loading mode it is **required** to specify this generic paramater.
+    /// This is currently true for `PgConnection`.
     ///
     /// When this method is called on [`sql_query`],
     /// the return type can only be a struct which implements [`QueryableByName`]
@@ -1528,8 +1549,10 @@ pub trait RunQueryDsl<Conn>: Sized {
     /// #     use diesel::insert_into;
     /// #     use schema::users::dsl::*;
     /// #     let connection = &mut establish_connection();
+    /// use diesel::connection::DefaultLoadingMode;
+    ///
     /// let data = users.select(name)
-    ///     .load_iter::<String>(connection)?
+    ///     .load_iter::<String, DefaultLoadingMode>(connection)?
     ///     .collect::<QueryResult<Vec<_>>>()?;
     /// assert_eq!(vec!["Sean", "Tess"], data);
     /// #     Ok(())
@@ -1549,8 +1572,10 @@ pub trait RunQueryDsl<Conn>: Sized {
     /// #     use diesel::insert_into;
     /// #     use schema::users::dsl::*;
     /// #     let connection = &mut establish_connection();
+    /// use diesel::connection::DefaultLoadingMode;
+    ///
     /// let data = users
-    ///     .load_iter::<(i32, String)>(connection)?
+    ///     .load_iter::<(i32, String), DefaultLoadingMode>(connection)?
     ///     .collect::<QueryResult<Vec<_>>>()?;
     /// let expected_data = vec![
     ///     (1, String::from("Sean")),
@@ -1580,8 +1605,10 @@ pub trait RunQueryDsl<Conn>: Sized {
     /// #     use diesel::insert_into;
     /// #     use schema::users::dsl::*;
     /// #     let connection = &mut establish_connection();
+    /// use diesel::connection::DefaultLoadingMode;
+    ///
     /// let data = users
-    ///     .load_iter::<User>(connection)?
+    ///     .load_iter::<User, DefaultLoadingMode>(connection)?
     ///     .collect::<QueryResult<Vec<_>>>()?;
     /// let expected_data = vec![
     ///     User { id: 1, name: String::from("Sean") },
@@ -1591,13 +1618,13 @@ pub trait RunQueryDsl<Conn>: Sized {
     /// #     Ok(())
     /// # }
     /// ```
-    fn load_iter<'conn, 'query: 'conn, U>(
+    fn load_iter<'conn, 'query: 'conn, U, B>(
         self,
         conn: &'conn mut Conn,
-    ) -> QueryResult<LoadIter<'conn, 'query, Self, Conn, U>>
+    ) -> QueryResult<LoadIter<'conn, 'query, Self, Conn, U, B>>
     where
         U: 'conn,
-        Self: LoadQuery<'query, Conn, U> + 'conn,
+        Self: LoadQuery<'query, Conn, U, B> + 'conn,
     {
         self.internal_load(conn)
     }
diff --git a/diesel/src/query_source/aliasing/alias.rs b/diesel/src/query_source/aliasing/alias.rs
index 1b256ec25a64..7167dbd59093 100644
--- a/diesel/src/query_source/aliasing/alias.rs
+++ b/diesel/src/query_source/aliasing/alias.rs
@@ -13,7 +13,7 @@ use std::marker::PhantomData;
 #[derive(Debug, Clone, Copy, Default)]
 /// Represents an alias within diesel's query builder
 ///
-/// See [alias!] for more details.
+/// See [`alias!`](crate::alias) for more details.
 pub struct Alias<S> {
     pub(crate) source: S,
 }
diff --git a/diesel/src/query_source/aliasing/aliased_field.rs b/diesel/src/query_source/aliasing/aliased_field.rs
index 0058885b5bbd..b8dc1c34b04f 100644
--- a/diesel/src/query_source/aliasing/aliased_field.rs
+++ b/diesel/src/query_source/aliasing/aliased_field.rs
@@ -16,7 +16,7 @@ use std::marker::PhantomData;
 #[derive(Debug, Clone, Copy)]
 /// Represents an aliased field (column) within diesel's query builder
 ///
-/// See [alias!] for more details.
+/// See [`alias!`](crate::alias) for more details.
 pub struct AliasedField<S, F> {
     pub(super) _alias_source: PhantomData<S>,
     pub(super) _field: F,
diff --git a/diesel/src/query_source/mod.rs b/diesel/src/query_source/mod.rs
index 1a1a07eebbeb..aaf1be08060f 100644
--- a/diesel/src/query_source/mod.rs
+++ b/diesel/src/query_source/mod.rs
@@ -32,6 +32,9 @@ pub trait QuerySource {
 
     /// The actual `FROM` clause of this type. This is typically only called in
     /// `QueryFragment` implementations.
+    // from here is something different than from in rust
+    // as this literally refercs to SQL from.
+    #[allow(clippy::wrong_self_convention)]
     fn from_clause(&self) -> Self::FromClause;
     /// The default select clause of this type, which should be used if no
     /// select clause was explicitly specified. This should always be a tuple of
diff --git a/diesel/src/r2d2.rs b/diesel/src/r2d2.rs
index ddac7c96e818..1256832d0a83 100644
--- a/diesel/src/r2d2.rs
+++ b/diesel/src/r2d2.rs
@@ -78,16 +78,18 @@
 //!
 //! When used inside a pool, if an individual connection becomes
 //! broken (as determined by the [R2D2Connection::is_broken] method)
-//! then `r2d2` will close and return the connection to the DB.
+//! then, when the connection goes out of scope, `r2d2` will close
+//! and return the connection to the DB.
 //!
 //! `diesel` determines broken connections by whether or not the current
 //! thread is panicking or if individual `Connection` structs are
 //! broken (determined by the `is_broken()` method). Generically, these
 //! are left to individual backends to implement themselves.
 //!
-//! For SQLite, PG, and MySQL backends, specifically, `is_broken()`
-//! is determined by whether or not the `TransactionManagerStatus` (as a part
-//! of the `AnsiTransactionManager` struct) is in an `InError` state.
+//! For SQLite, PG, and MySQL backends `is_broken()` is determined
+//! by whether or not the `TransactionManagerStatus` (as a part
+//! of the `AnsiTransactionManager` struct) is in an `InError` state
+//! or contains an open transaction when the connection goes out of scope.
 //!
 
 pub use r2d2::*;
@@ -103,9 +105,9 @@ use std::fmt;
 use std::marker::PhantomData;
 
 use crate::backend::Backend;
-use crate::connection::commit_error_processor::{CommitErrorOutcome, CommitErrorProcessor};
 use crate::connection::{
-    ConnectionGatWorkaround, SimpleConnection, TransactionManager, TransactionManagerStatus,
+    ConnectionGatWorkaround, LoadConnection, LoadRowIter, SimpleConnection, TransactionManager,
+    TransactionManagerStatus,
 };
 use crate::expression::QueryMetadata;
 use crate::prelude::*;
@@ -209,24 +211,14 @@ where
     }
 }
 
-impl<'conn, 'query, DB, M> ConnectionGatWorkaround<'conn, 'query, DB> for PooledConnection<M>
+impl<'conn, 'query, DB, M, B> ConnectionGatWorkaround<'conn, 'query, DB, B> for PooledConnection<M>
 where
     M: ManageConnection,
-    M::Connection: Connection<Backend = DB>,
+    M::Connection: Connection<Backend = DB> + ConnectionGatWorkaround<'conn, 'query, DB, B>,
     DB: Backend,
 {
-    type Cursor = <M::Connection as ConnectionGatWorkaround<'conn, 'query, DB>>::Cursor;
-    type Row = <M::Connection as ConnectionGatWorkaround<'conn, 'query, DB>>::Row;
-}
-
-impl<M> CommitErrorProcessor for PooledConnection<M>
-where
-    M: ManageConnection,
-    M::Connection: R2D2Connection + CommitErrorProcessor + Send + 'static,
-{
-    fn process_commit_error(&self, error: crate::result::Error) -> CommitErrorOutcome {
-        (&**self).process_commit_error(error)
-    }
+    type Cursor = <M::Connection as ConnectionGatWorkaround<'conn, 'query, DB, B>>::Cursor;
+    type Row = <M::Connection as ConnectionGatWorkaround<'conn, 'query, DB, B>>::Row;
 }
 
 impl<M> Connection for PooledConnection<M>
@@ -244,17 +236,6 @@ where
         )))
     }
 
-    fn load<'conn, 'query, T>(
-        &'conn mut self,
-        source: T,
-    ) -> QueryResult<<Self as ConnectionGatWorkaround<'conn, 'query, Self::Backend>>::Cursor>
-    where
-        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
-        Self::Backend: QueryMetadata<T::SqlType>,
-    {
-        (&mut **self).load(source)
-    }
-
     fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
     where
         T: QueryFragment<Self::Backend> + QueryId,
@@ -273,6 +254,23 @@ where
     }
 }
 
+impl<B, M> LoadConnection<B> for PooledConnection<M>
+where
+    M: ManageConnection,
+    M::Connection: LoadConnection<B> + R2D2Connection,
+{
+    fn load<'conn, 'query, T>(
+        &'conn mut self,
+        source: T,
+    ) -> QueryResult<LoadRowIter<'conn, 'query, Self, Self::Backend, B>>
+    where
+        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
+        Self::Backend: QueryMetadata<T::SqlType>,
+    {
+        (&mut **self).load(source)
+    }
+}
+
 #[doc(hidden)]
 #[allow(missing_debug_implementations)]
 pub struct PoolTransactionManager<T>(std::marker::PhantomData<T>);
@@ -327,6 +325,28 @@ where
     }
 }
 
+#[derive(QueryId)]
+pub(crate) struct CheckConnectionQuery;
+
+impl<DB> QueryFragment<DB> for CheckConnectionQuery
+where
+    DB: Backend,
+{
+    fn walk_ast<'b>(
+        &'b self,
+        mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
+    ) -> QueryResult<()> {
+        pass.push_sql("SELECT 1");
+        Ok(())
+    }
+}
+
+impl Query for CheckConnectionQuery {
+    type SqlType = crate::sql_types::Integer;
+}
+
+impl<C> RunQueryDsl<C> for CheckConnectionQuery {}
+
 #[cfg(test)]
 mod tests {
     use std::sync::mpsc;
@@ -394,26 +414,118 @@ mod tests {
         let query = select("foo".into_sql::<Text>());
         assert_eq!("foo", query.get_result::<String>(&mut conn).unwrap());
     }
-}
 
-#[derive(QueryId)]
-pub(crate) struct CheckConnectionQuery;
+    #[test]
+    fn check_pool_does_actually_hold_connections() {
+        use std::sync::atomic::{AtomicU32, Ordering};
+
+        #[derive(Debug)]
+        struct TestEventHandler {
+            acquire_count: Arc<AtomicU32>,
+            release_count: Arc<AtomicU32>,
+            checkin_count: Arc<AtomicU32>,
+            checkout_count: Arc<AtomicU32>,
+        }
 
-impl<DB> QueryFragment<DB> for CheckConnectionQuery
-where
-    DB: Backend,
-{
-    fn walk_ast<'b>(
-        &'b self,
-        mut pass: crate::query_builder::AstPass<'_, 'b, DB>,
-    ) -> QueryResult<()> {
-        pass.push_sql("SELECT 1");
-        Ok(())
-    }
-}
+        impl r2d2::HandleEvent for TestEventHandler {
+            fn handle_acquire(&self, _event: r2d2::event::AcquireEvent) {
+                self.acquire_count.fetch_add(1, Ordering::Relaxed);
+            }
+            fn handle_release(&self, _event: r2d2::event::ReleaseEvent) {
+                self.release_count.fetch_add(1, Ordering::Relaxed);
+            }
+            fn handle_checkout(&self, _event: r2d2::event::CheckoutEvent) {
+                self.checkout_count.fetch_add(1, Ordering::Relaxed);
+            }
+            fn handle_checkin(&self, _event: r2d2::event::CheckinEvent) {
+                self.checkin_count.fetch_add(1, Ordering::Relaxed);
+            }
+        }
 
-impl Query for CheckConnectionQuery {
-    type SqlType = crate::sql_types::Integer;
-}
+        let acquire_count = Arc::new(AtomicU32::new(0));
+        let release_count = Arc::new(AtomicU32::new(0));
+        let checkin_count = Arc::new(AtomicU32::new(0));
+        let checkout_count = Arc::new(AtomicU32::new(0));
 
-impl<C> RunQueryDsl<C> for CheckConnectionQuery {}
+        let handler = Box::new(TestEventHandler {
+            acquire_count: acquire_count.clone(),
+            release_count: release_count.clone(),
+            checkin_count: checkin_count.clone(),
+            checkout_count: checkout_count.clone(),
+        });
+
+        let manager = ConnectionManager::<TestConnection>::new(database_url());
+        let pool = Pool::builder()
+            .max_size(1)
+            .test_on_check_out(true)
+            .event_handler(handler)
+            .build(manager)
+            .unwrap();
+
+        assert_eq!(acquire_count.load(Ordering::Relaxed), 1);
+        assert_eq!(release_count.load(Ordering::Relaxed), 0);
+        assert_eq!(checkin_count.load(Ordering::Relaxed), 0);
+        assert_eq!(checkout_count.load(Ordering::Relaxed), 0);
+
+        // check that we reuse connections with the pool
+        {
+            let conn = pool.get().unwrap();
+
+            assert_eq!(acquire_count.load(Ordering::Relaxed), 1);
+            assert_eq!(release_count.load(Ordering::Relaxed), 0);
+            assert_eq!(checkin_count.load(Ordering::Relaxed), 0);
+            assert_eq!(checkout_count.load(Ordering::Relaxed), 1);
+            std::mem::drop(conn);
+        }
+
+        assert_eq!(acquire_count.load(Ordering::Relaxed), 1);
+        assert_eq!(release_count.load(Ordering::Relaxed), 0);
+        assert_eq!(checkin_count.load(Ordering::Relaxed), 1);
+        assert_eq!(checkout_count.load(Ordering::Relaxed), 1);
+
+        // check that we remove a connection with open transactions from the pool
+        {
+            let mut conn = pool.get().unwrap();
+
+            assert_eq!(acquire_count.load(Ordering::Relaxed), 1);
+            assert_eq!(release_count.load(Ordering::Relaxed), 0);
+            assert_eq!(checkin_count.load(Ordering::Relaxed), 1);
+            assert_eq!(checkout_count.load(Ordering::Relaxed), 2);
+
+            <TestConnection as Connection>::TransactionManager::begin_transaction(&mut *conn)
+                .unwrap();
+        }
+
+        // we are not interested in the acquire count here
+        // as the pool opens a new connection in the background
+        // that could lead to this test failing if that happens to fast
+        // (which is sometimes the case for sqlite)
+        //assert_eq!(acquire_count.load(Ordering::Relaxed), 1);
+        assert_eq!(release_count.load(Ordering::Relaxed), 1);
+        assert_eq!(checkin_count.load(Ordering::Relaxed), 2);
+        assert_eq!(checkout_count.load(Ordering::Relaxed), 2);
+
+        // check that we remove a connection from the pool that was
+        // open during panicing
+        #[allow(unreachable_code, unused_variables)]
+        std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
+            let conn = pool.get();
+            assert_eq!(acquire_count.load(Ordering::Relaxed), 2);
+            assert_eq!(release_count.load(Ordering::Relaxed), 1);
+            assert_eq!(checkin_count.load(Ordering::Relaxed), 2);
+            assert_eq!(checkout_count.load(Ordering::Relaxed), 3);
+            panic!();
+            std::mem::drop(conn);
+        }))
+        .unwrap_err();
+
+        // we are not interested in the acquire count here
+        // as the pool opens a new connection in the background
+        // that could lead to this test failing if that happens to fast
+        // (which is sometimes the case for sqlite)
+        //assert_eq!(acquire_count.load(Ordering::Relaxed), 2);
+        assert_eq!(release_count.load(Ordering::Relaxed), 2);
+        assert_eq!(checkin_count.load(Ordering::Relaxed), 3);
+        assert_eq!(checkout_count.load(Ordering::Relaxed), 3);
+    }
+}
diff --git a/diesel/src/result.rs b/diesel/src/result.rs
index 7a0a12925fdf..f864fb136365 100644
--- a/diesel/src/result.rs
+++ b/diesel/src/result.rs
@@ -62,11 +62,21 @@ pub enum Error {
     /// by PostgreSQL.
     SerializationError(Box<dyn StdError + Send + Sync>),
 
-    /// An error occurred during the rollback of a transaction.
+    /// An error occurred when attempting rollback of a transaction subsequently to a failed
+    /// commit attempt.
     ///
-    /// An example of when this error would be returned is if a rollback has
-    /// already be called on the current transaction.
-    RollbackError(Box<Error>),
+    /// When a commit attempt fails and Diesel beleives that it can attempt a rollback to return
+    /// the connection back in a usable state (out of that transaction), it attempts it then
+    /// returns the original error.
+    ///
+    /// If that fails, you get this.
+    RollbackErrorOnCommit {
+        /// The error that was encoutered when attempting the rollback
+        rollback_error: Box<Error>,
+        /// If the rollback attempt resulted from a failed attempt to commit the transaction,
+        /// you will find the related error here.
+        commit_error: Box<Error>,
+    },
 
     /// Roll back the current transaction.
     ///
@@ -84,20 +94,8 @@ pub enum Error {
     /// when no transaction was open
     NotInTransaction,
 
-    /// Transaction broken, likely due to a broken connection. No other operations are possible.
-    BrokenTransaction,
-
-    /// Commiting a transaction failed
-    ///
-    /// The transaction manager will try to perform
-    /// a rollback in such cases. Indications about the success
-    /// of this can be extracted from this error variant
-    CommitTransactionFailed {
-        /// Failure message of the commit attempt
-        commit_error: Box<Error>,
-        /// Outcome of the rollback attempt
-        rollback_result: Box<QueryResult<()>>,
-    },
+    /// Transaction manager broken, likely due to a broken connection. No other operations are possible.
+    BrokenTransactionManager,
 }
 
 #[derive(Debug, Clone, Copy)]
@@ -314,9 +312,22 @@ impl Display for Error {
             Error::QueryBuilderError(ref e) => e.fmt(f),
             Error::DeserializationError(ref e) => e.fmt(f),
             Error::SerializationError(ref e) => e.fmt(f),
-            Error::RollbackError(ref e) => e.fmt(f),
-            Error::RollbackTransaction => write!(f, "The current transaction was aborted"),
-            Error::BrokenTransaction => write!(f, "The current transaction is broken"),
+            Error::RollbackErrorOnCommit {
+                ref rollback_error,
+                ref commit_error,
+            } => {
+                write!(
+                    f,
+                    "Transaction rollback failed: {} \
+                        (rollback attempted because of failure to commit: {})",
+                    &**rollback_error, &**commit_error
+                )?;
+                Ok(())
+            }
+            Error::RollbackTransaction => {
+                write!(f, "You have asked diesel to rollback the transaction")
+            }
+            Error::BrokenTransactionManager => write!(f, "The transaction manager is broken"),
             Error::AlreadyInTransaction => write!(
                 f,
                 "Cannot perform this operation while a transaction is open",
@@ -324,20 +335,6 @@ impl Display for Error {
             Error::NotInTransaction => {
                 write!(f, "Cannot perform this operation outside of a transaction",)
             }
-            Error::CommitTransactionFailed {
-                ref commit_error,
-                ref rollback_result,
-            } => {
-                write!(
-                    f,
-                    "Commiting the current transaction failed: {}",
-                    commit_error
-                )?;
-                match &**rollback_result {
-                    Ok(()) => write!(f, " Rollback attempt was succesful"),
-                    Err(e) => write!(f, " Rollback attempt failed with {}", e),
-                }
-            }
         }
     }
 }
diff --git a/diesel/src/sqlite/backend.rs b/diesel/src/sqlite/backend.rs
index 0e9014a6855f..f2550de61aae 100644
--- a/diesel/src/sqlite/backend.rs
+++ b/diesel/src/sqlite/backend.rs
@@ -57,9 +57,9 @@ impl SqlDialect for Sqlite {
     #[cfg(not(feature = "returning_clauses_for_sqlite_3_35"))]
     type ReturningClause = sql_dialect::returning_clause::DoesNotSupportReturningClause;
     #[cfg(feature = "returning_clauses_for_sqlite_3_35")]
-    type ReturningClause = sql_dialect::returning_clause::PgLikeReturningClause;
+    type ReturningClause = SqliteReturningClause;
 
-    type OnConflictClause = SqliteOnConflictClaues;
+    type OnConflictClause = SqliteOnConflictClause;
 
     type InsertWithDefaultKeyword =
         sql_dialect::default_keyword_for_insert::DoesNotSupportDefaultKeyword;
@@ -68,16 +68,21 @@ impl SqlDialect for Sqlite {
 
     type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax;
     type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax;
-    type ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison;
+    type ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison;
 }
 
 impl DieselReserveSpecialization for Sqlite {}
 impl TrustedBackend for Sqlite {}
 
 #[derive(Debug, Copy, Clone)]
-pub struct SqliteOnConflictClaues;
+pub struct SqliteOnConflictClause;
 
-impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for SqliteOnConflictClaues {}
+impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for SqliteOnConflictClause {}
 
 #[derive(Debug, Copy, Clone)]
 pub struct SqliteBatchInsert;
+
+#[derive(Debug, Copy, Clone)]
+pub struct SqliteReturningClause;
+
+impl sql_dialect::returning_clause::SupportsReturningClause for SqliteReturningClause {}
diff --git a/diesel/src/sqlite/connection/functions.rs b/diesel/src/sqlite/connection/functions.rs
index 6fed6485f4f2..1fdf00043a77 100644
--- a/diesel/src/sqlite/connection/functions.rs
+++ b/diesel/src/sqlite/connection/functions.rs
@@ -96,6 +96,9 @@ where
     Args::build_from_row(&row).map_err(Error::DeserializationError)
 }
 
+// clippy is wrong here, the let binding is required
+// for lifetime reasons
+#[allow(clippy::let_unit_value)]
 pub(super) fn process_sql_function_result<RetSqlType, Ret>(
     result: &'_ Ret,
 ) -> QueryResult<InternalSqliteBindValue<'_>>
diff --git a/diesel/src/sqlite/connection/mod.rs b/diesel/src/sqlite/connection/mod.rs
index 3d85958519ba..509e463fb6f6 100644
--- a/diesel/src/sqlite/connection/mod.rs
+++ b/diesel/src/sqlite/connection/mod.rs
@@ -18,9 +18,6 @@ use self::raw::RawConnection;
 use self::statement_iterator::*;
 use self::stmt::{Statement, StatementUse};
 use super::SqliteAggregateFunction;
-use crate::connection::commit_error_processor::{
-    default_process_commit_error, CommitErrorOutcome, CommitErrorProcessor,
-};
 use crate::connection::statement_cache::StatementCache;
 use crate::connection::*;
 use crate::deserialize::{FromSqlRow, StaticallySizedRow};
@@ -37,6 +34,83 @@ use crate::sqlite::Sqlite;
 /// - File paths (`test.db`)
 /// - [URIs](https://sqlite.org/uri.html) (`file://test.db`)
 /// - Special identifiers (`:memory:`)
+///
+/// # Supported loading model implementations
+///
+/// * [`DefaultLoadingMode`]
+///
+/// As `SqliteConnection` only supports a single loading mode implementation
+/// it is **not required** to explicitly specify a loading mode
+/// when calling [`RunQueryDsl::load_iter()`] or [`LoadConnection::load`]
+///
+/// [`RunQueryDsl::load_iter()`]: crate::query_dsl::RunQueryDsl::load_iter
+///
+/// ## DefaultLoadingMode
+///
+/// `SqliteConnection` only supports a single loading mode, which loads
+/// values row by row from the result set.
+///
+/// ```rust
+/// # include!("../../doctest_setup.rs");
+/// #
+/// # fn main() {
+/// #     run_test().unwrap();
+/// # }
+/// #
+/// # fn run_test() -> QueryResult<()> {
+/// #     use schema::users;
+/// #     let connection = &mut establish_connection();
+/// use diesel::connection::DefaultLoadingMode;
+/// { // scope to restrict the lifetime of the iterator
+///     let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
+///
+///     for r in iter1 {
+///         let (id, name) = r?;
+///         println!("Id: {} Name: {}", id, name);
+///     }
+/// }
+///
+/// // works without specifying the loading mode
+/// let iter2 = users::table.load_iter::<(i32, String), _>(connection)?;
+///
+/// for r in iter2 {
+///     let (id, name) = r?;
+///     println!("Id: {} Name: {}", id, name);
+/// }
+/// #   Ok(())
+/// # }
+/// ```
+///
+/// This mode does **not support** creating
+/// multiple iterators using the same connection.
+///
+/// ```compile_fail
+/// # include!("../../doctest_setup.rs");
+/// #
+/// # fn main() {
+/// #     run_test().unwrap();
+/// # }
+/// #
+/// # fn run_test() -> QueryResult<()> {
+/// #     use schema::users;
+/// #     let connection = &mut establish_connection();
+/// use diesel::connection::DefaultLoadingMode;
+///
+/// let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
+/// let iter2 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
+///
+/// for r in iter1 {
+///     let (id, name) = r?;
+///     println!("Id: {} Name: {}", id, name);
+/// }
+///
+/// for r in iter2 {
+///     let (id, name) = r?;
+///     println!("Id: {} Name: {}", id, name);
+/// }
+/// #   Ok(())
+/// # }
+/// ```
 #[allow(missing_debug_implementations)]
 #[cfg(feature = "sqlite")]
 pub struct SqliteConnection {
@@ -64,18 +138,6 @@ impl<'conn, 'query> ConnectionGatWorkaround<'conn, 'query, Sqlite> for SqliteCon
     type Row = self::row::SqliteRow<'conn, 'query>;
 }
 
-impl CommitErrorProcessor for SqliteConnection {
-    fn process_commit_error(&self, error: Error) -> CommitErrorOutcome {
-        let state = match self.transaction_state.status {
-            TransactionManagerStatus::InError => {
-                return CommitErrorOutcome::Throw(Error::BrokenTransaction)
-            }
-            TransactionManagerStatus::Valid(ref v) => v,
-        };
-        default_process_commit_error(state, error)
-    }
-}
-
 impl Connection for SqliteConnection {
     type Backend = Sqlite;
     type TransactionManager = AnsiTransactionManager;
@@ -100,20 +162,6 @@ impl Connection for SqliteConnection {
         Ok(conn)
     }
 
-    fn load<'conn, 'query, T>(
-        &'conn mut self,
-        source: T,
-    ) -> QueryResult<LoadRowIter<'conn, 'query, Self, Self::Backend>>
-    where
-        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
-        Self::Backend: QueryMetadata<T::SqlType>,
-    {
-        let statement_use = self.prepared_query(source)?;
-
-        Ok(StatementIterator::new(statement_use))
-    }
-
-    #[doc(hidden)]
     fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
     where
         T: QueryFragment<Self::Backend> + QueryId,
@@ -132,6 +180,21 @@ impl Connection for SqliteConnection {
     }
 }
 
+impl LoadConnection<DefaultLoadingMode> for SqliteConnection {
+    fn load<'conn, 'query, T>(
+        &'conn mut self,
+        source: T,
+    ) -> QueryResult<LoadRowIter<'conn, 'query, Self, Self::Backend>>
+    where
+        T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
+        Self::Backend: QueryMetadata<T::SqlType>,
+    {
+        let statement_use = self.prepared_query(source)?;
+
+        Ok(StatementIterator::new(statement_use))
+    }
+}
+
 #[cfg(feature = "r2d2")]
 impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection {
     fn ping(&mut self) -> QueryResult<()> {
@@ -141,11 +204,15 @@ impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection {
     }
 
     fn is_broken(&mut self) -> bool {
-        self.transaction_state
-            .status
-            .transaction_depth()
-            .map(|d| d.is_none())
-            .unwrap_or(true)
+        match self.transaction_state.status.transaction_depth() {
+            // all transactions are closed
+            // so we don't consider this connection broken
+            Ok(None) => false,
+            // The transaction manager is in an error state
+            // or contains an open transaction
+            // Therefore we consider this connection broken
+            Err(_) | Ok(Some(_)) => true,
+        }
     }
 }
 
@@ -453,7 +520,7 @@ mod tests {
     #[test]
     fn register_noarg_function() {
         let connection = &mut SqliteConnection::establish(":memory:").unwrap();
-        answer::register_impl(&connection, || 42).unwrap();
+        answer::register_impl(connection, || 42).unwrap();
 
         let answer = crate::select(answer()).get_result::<i32>(connection);
         assert_eq!(Ok(42), answer);
@@ -462,7 +529,7 @@ mod tests {
     #[test]
     fn register_nondeterministic_noarg_function() {
         let connection = &mut SqliteConnection::establish(":memory:").unwrap();
-        answer::register_nondeterministic_impl(&connection, || 42).unwrap();
+        answer::register_nondeterministic_impl(connection, || 42).unwrap();
 
         let answer = crate::select(answer()).get_result::<i32>(connection);
         assert_eq!(Ok(42), answer);
diff --git a/diesel/src/sqlite/connection/raw.rs b/diesel/src/sqlite/connection/raw.rs
index d7571b58f8f0..247f65abaa73 100644
--- a/diesel/src/sqlite/connection/raw.rs
+++ b/diesel/src/sqlite/connection/raw.rs
@@ -475,7 +475,6 @@ extern "C" fn run_aggregator_final_function<ArgsSqlType, RetSqlType, Args, Ret,
     });
     if let Err(e) = result {
         e.emit(ctx);
-        return;
     }
 }
 
diff --git a/diesel/src/sqlite/connection/row.rs b/diesel/src/sqlite/connection/row.rs
index 36a1f5fa07e1..9caa84cc4464 100644
--- a/diesel/src/sqlite/connection/row.rs
+++ b/diesel/src/sqlite/connection/row.rs
@@ -147,6 +147,7 @@ fn fun_with_row_iters() {
         }
     }
 
+    use crate::connection::LoadConnection;
     use crate::deserialize::{FromSql, FromSqlRow};
     use crate::prelude::*;
     use crate::row::{Field, Row};
diff --git a/diesel/src/sqlite/query_builder/mod.rs b/diesel/src/sqlite/query_builder/mod.rs
index 546c963445d6..dc0f522175ac 100644
--- a/diesel/src/sqlite/query_builder/mod.rs
+++ b/diesel/src/sqlite/query_builder/mod.rs
@@ -5,6 +5,7 @@ use crate::query_builder::QueryBuilder;
 use crate::result::QueryResult;
 
 mod limit_offset;
+mod returning;
 
 /// Constructs SQL queries for use with the SQLite backend
 #[allow(missing_debug_implementations)]
@@ -27,7 +28,7 @@ impl QueryBuilder<Sqlite> for SqliteQueryBuilder {
 
     fn push_identifier(&mut self, identifier: &str) -> QueryResult<()> {
         self.push_sql("`");
-        self.push_sql(&identifier.replace("`", "``"));
+        self.push_sql(&identifier.replace('`', "``"));
         self.push_sql("`");
         Ok(())
     }
diff --git a/diesel/src/sqlite/query_builder/returning.rs b/diesel/src/sqlite/query_builder/returning.rs
new file mode 100644
index 000000000000..fa626f840d14
--- /dev/null
+++ b/diesel/src/sqlite/query_builder/returning.rs
@@ -0,0 +1,18 @@
+use crate::backend::Backend;
+use crate::query_builder::returning_clause::ReturningClause;
+use crate::query_builder::{AstPass, QueryFragment};
+use crate::result::QueryResult;
+use crate::sqlite::backend::SqliteReturningClause;
+
+impl<Expr, DB> QueryFragment<DB, SqliteReturningClause> for ReturningClause<Expr>
+where
+    DB: Backend<ReturningClause = SqliteReturningClause>,
+    Expr: QueryFragment<DB>,
+{
+    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
+        out.skip_from(true);
+        out.push_sql(" RETURNING ");
+        self.0.walk_ast(out.reborrow())?;
+        Ok(())
+    }
+}
diff --git a/diesel/src/type_impls/option.rs b/diesel/src/type_impls/option.rs
index 929255311f10..b61615a8309e 100644
--- a/diesel/src/type_impls/option.rs
+++ b/diesel/src/type_impls/option.rs
@@ -5,6 +5,7 @@ use crate::expression::*;
 use crate::query_builder::QueryId;
 use crate::serialize::{self, IsNull, Output, ToSql};
 use crate::sql_types::{is_nullable, HasSqlType, Nullable, SingleValue, SqlType};
+use crate::NullableExpressionMethods;
 
 impl<T, DB> HasSqlType<Nullable<T>> for DB
 where
@@ -109,15 +110,25 @@ where
     }
 }
 
-#[cfg(all(test, feature = "postgres"))]
-use crate::pg::Pg;
-#[cfg(all(test, feature = "postgres"))]
-use crate::sql_types;
+impl<T, DB> Selectable<DB> for Option<T>
+where
+    DB: Backend,
+    T: Selectable<DB>,
+    crate::dsl::Nullable<T::SelectExpression>: Expression,
+{
+    type SelectExpression = crate::dsl::Nullable<T::SelectExpression>;
+
+    fn construct_selection() -> Self::SelectExpression {
+        T::construct_selection().nullable()
+    }
+}
 
 #[test]
 #[cfg(feature = "postgres")]
 fn option_to_sql() {
+    use crate::pg::Pg;
     use crate::query_builder::bind_collector::ByteWrapper;
+    use crate::sql_types;
 
     type Type = sql_types::Nullable<sql_types::VarChar>;
 
diff --git a/diesel/src/type_impls/tuples.rs b/diesel/src/type_impls/tuples.rs
index df6af762ed78..ade4495375e5 100644
--- a/diesel/src/type_impls/tuples.rs
+++ b/diesel/src/type_impls/tuples.rs
@@ -5,8 +5,8 @@ use crate::deserialize::{
 };
 use crate::expression::{
     is_contained_in_group_by, AppearsOnTable, AsExpression, AsExpressionList, Expression,
-    IsContainedInGroupBy, QueryMetadata, Selectable, SelectableExpression, TypedExpressionType,
-    ValidGrouping,
+    IsContainedInGroupBy, MixedAggregates, QueryMetadata, Selectable, SelectableExpression,
+    TypedExpressionType, ValidGrouping,
 };
 use crate::insertable::{CanInsertInSingleQuery, InsertValues, Insertable, InsertableOptionHelper};
 use crate::query_builder::*;
@@ -114,12 +114,6 @@ macro_rules! tuple_impls {
                 const HAS_STATIC_QUERY_ID: bool = $($T::HAS_STATIC_QUERY_ID &&)+ true;
             }
 
-            const _: () = {
-                #[derive(ValidGrouping)]
-                #[diesel(foreign_derive)]
-                struct TupleWrapper<$($T,)*>(($($T,)*));
-            };
-
             impl_valid_grouping_for_tuple_of_columns!($($T,)*);
 
             impl<$($T,)+ Tab> UndecoratedInsertRecord<Tab> for ($($T,)+)
@@ -453,49 +447,23 @@ macro_rules! impl_from_sql_row {
 }
 
 macro_rules! impl_valid_grouping_for_tuple_of_columns {
-    (
-        @build
-        start_ts = [$($ST: ident,)*],
-        ts = [$T1: ident,],
-        bounds = [$($bounds: tt)*],
-        is_aggregate = [$($is_aggregate: tt)*],
-    ) => {
-        impl<$($ST,)* Col> IsContainedInGroupBy<Col> for ($($ST,)*)
-        where Col: Column,
-            $($ST: IsContainedInGroupBy<Col>,)*
-            $($bounds)*
-            <$T1 as IsContainedInGroupBy<Col>>::Output: is_contained_in_group_by::IsAny<$($is_aggregate)*>,
+    ($T1: ident, $($T: ident,)+) => {
+        impl<$T1, $($T,)* __GroupByClause> ValidGrouping<__GroupByClause> for ($T1, $($T,)*)
+        where
+            $T1: ValidGrouping<__GroupByClause>,
+            ($($T,)*): ValidGrouping<__GroupByClause>,
+            $T1::IsAggregate: MixedAggregates<<($($T,)*) as ValidGrouping<__GroupByClause>>::IsAggregate>,
         {
-            type Output = <<$T1 as IsContainedInGroupBy<Col>>::Output as is_contained_in_group_by::IsAny<$($is_aggregate)*>>::Output;
-        }
-    };
-    (
-        @build
-        start_ts = [$($ST: ident,)*],
-        ts = [$T1: ident, $($T: ident,)+],
-        bounds = [$($bounds: tt)*],
-        is_aggregate = [$($is_aggregate: tt)*],
-    ) => {
-        impl_valid_grouping_for_tuple_of_columns! {
-            @build
-            start_ts = [$($ST,)*],
-            ts = [$($T,)*],
-            bounds = [
-                $($bounds)*
-                <$T1 as IsContainedInGroupBy<Col>>::Output: is_contained_in_group_by::IsAny<$($is_aggregate)*>,
-            ],
-            is_aggregate = [
-                <<$T1 as IsContainedInGroupBy<Col>>::Output as is_contained_in_group_by::IsAny<$($is_aggregate)*>>::Output
-            ],
+            type IsAggregate = <$T1::IsAggregate as MixedAggregates<<($($T,)*) as ValidGrouping<__GroupByClause>>::IsAggregate>>::Output;
         }
-    };
-    ($T1: ident, $($T: ident,)+) => {
-        impl_valid_grouping_for_tuple_of_columns! {
-            @build
-            start_ts = [$T1, $($T,)*],
-            ts = [$($T,)*],
-            bounds = [],
-            is_aggregate = [<$T1 as IsContainedInGroupBy<Col>>::Output],
+
+        impl<$T1, $($T,)* Col> IsContainedInGroupBy<Col> for ($T1, $($T,)*)
+        where Col: Column,
+              ($($T,)*): IsContainedInGroupBy<Col>,
+              $T1: IsContainedInGroupBy<Col>,
+              $T1::Output: is_contained_in_group_by::IsAny<<($($T,)*) as IsContainedInGroupBy<Col>>::Output>
+        {
+            type Output = <$T1::Output as is_contained_in_group_by::IsAny<<($($T,)*) as IsContainedInGroupBy<Col>>::Output>>::Output;
         }
     };
     ($T1: ident,) => {
@@ -505,6 +473,12 @@ macro_rules! impl_valid_grouping_for_tuple_of_columns {
         {
             type Output = <$T1 as IsContainedInGroupBy<Col>>::Output;
         }
+
+        impl<$T1, __GroupByClause> ValidGrouping<__GroupByClause> for ($T1,)
+            where $T1: ValidGrouping<__GroupByClause>
+        {
+            type IsAggregate = $T1::IsAggregate;
+        }
     };
 }
 
diff --git a/diesel_bench/Cargo.toml b/diesel_bench/Cargo.toml
index 3985a3adcffe..887f6d38d79a 100644
--- a/diesel_bench/Cargo.toml
+++ b/diesel_bench/Cargo.toml
@@ -22,7 +22,7 @@ quaint = {version = "=0.2.0-alpha.13", optional = true}
 serde = {version = "1", optional = true, features = ["derive"]}
 sea-orm = {version = "0.7", optional = true, features = ["runtime-tokio-rustls"]}
 futures = {version = "0.3", optional = true}
-diesel-async = {git = "https://github.com/weiznich/diesel_async", rev = "61183dc252e85935d3605f1e3206cd7065d456de", optional = true, default-features = false}
+#diesel-async = {git = "https://github.com/weiznich/diesel_async", rev = "61183dc252e85935d3605f1e3206cd7065d456de", optional = true, default-features = false}
 criterion-perf-events = { version = "0.2", optional = true}
 perfcnt = {version = "0.8", optional = true}
 
@@ -54,4 +54,4 @@ fast_run = []
 
 [replace]
 "quaint:0.2.0-alpha.13" = {git = "https://github.com/prisma/quaint", rev = "e077df3"}
-"https://github.com/diesel-rs/diesel#2.0.0-rc.0" = { path = "../diesel"}
+#"https://github.com/diesel-rs/diesel#2.0.0-rc.0" = { path = "../diesel"}
diff --git a/diesel_cli/Cargo.toml b/diesel_cli/Cargo.toml
index 854705ebea27..b5edc6196897 100644
--- a/diesel_cli/Cargo.toml
+++ b/diesel_cli/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "diesel_cli"
-version = "2.0.0-rc.0"
+version = "2.0.0-rc.1"
 license = "MIT OR Apache-2.0"
 description = "Provides the CLI for the Diesel crate"
 readme = "README.md"
@@ -11,7 +11,7 @@ keywords = ["diesel", "migrations", "cli"]
 autotests = false
 edition = "2018"
 include = ["src/**/*", "LICENSE-*", "README.md"]
-rust-version = "1.54.0"
+rust-version = "1.56.0"
 
 [[bin]]
 name = "diesel"
@@ -20,25 +20,25 @@ doc = false
 
 [dependencies]
 chrono = { version = "0.4.19", default-features = false, features = ["clock", "std"] }
-clap = "3.1"
-clap_complete = "3.1"
+clap = "3.2.1"
+clap_complete = "3.2"
 dotenvy = "0.15"
 heck = "0.4.0"
 serde = { version = "1.0.0", features = ["derive"] }
 toml = "0.5"
 url = { version = "2.1.0", optional = true }
-libsqlite3-sys = { version = ">=0.17.2, <0.25.0", optional = true }
+libsqlite3-sys = { version = ">=0.17.2, <0.26.0", optional = true }
 diffy = "0.2.0"
 regex = "1.0.6"
 serde_regex = "1.1"
 
 [dependencies.diesel]
-version = "~2.0.0-rc.0"
+version = "~2.0.0-rc.1"
 path = "../diesel"
 default-features = false
 
 [dependencies.diesel_migrations]
-version = "~2.0.0-rc.0"
+version = "~2.0.0-rc.1"
 path = "../diesel_migrations/"
 
 [dev-dependencies]
diff --git a/diesel_cli/src/cli.rs b/diesel_cli/src/cli.rs
index 52057793a8ca..e86aeb1ce864 100644
--- a/diesel_cli/src/cli.rs
+++ b/diesel_cli/src/cli.rs
@@ -1,11 +1,9 @@
-use crate::validators::num::*;
-use clap::{Arg, Command};
+use clap::{
+    builder::{EnumValueParser, PossibleValuesParser},
+    Arg, Command,
+};
 use clap_complete::Shell;
 
-fn str_as_char(str: &str) -> char {
-    str.chars().next().unwrap()
-}
-
 pub fn build_cli() -> Command<'static> {
     let database_arg = Arg::new("DATABASE_URL")
         .long("database-url")
@@ -29,7 +27,7 @@ pub fn build_cli() -> Command<'static> {
                 .arg(
                     Arg::new("REVERT_ALL")
                         .long("all")
-                        .short(str_as_char("a"))
+                        .short('a')
                         .help("Reverts previously run migration files.")
                         .takes_value(false)
                         .conflicts_with("REVERT_NUMBER"),
@@ -37,7 +35,7 @@ pub fn build_cli() -> Command<'static> {
                 .arg(
                     Arg::new("REVERT_NUMBER")
                         .long("number")
-                        .short(str_as_char("n"))
+                        .short('n')
                         .help("Reverts the last `n` migration files.")
                         .long_help(
                             "When this option is specified the last `n` migration files \
@@ -45,7 +43,7 @@ pub fn build_cli() -> Command<'static> {
                         )
                         .default_value("1")
                         .takes_value(true)
-                        .validator(is_positive_int)
+                        .value_parser(clap::value_parser!(u64))
                         .conflicts_with("REVERT_ALL"),
                 ),
         )
@@ -58,7 +56,7 @@ pub fn build_cli() -> Command<'static> {
                 .arg(
                     Arg::new("REDO_ALL")
                         .long("all")
-                        .short(str_as_char("a"))
+                        .short('a')
                         .help("Reverts and re-runs all migrations.")
                         .long_help(
                             "When this option is specified all migrations \
@@ -71,7 +69,7 @@ pub fn build_cli() -> Command<'static> {
                 .arg(
                     Arg::new("REDO_NUMBER")
                         .long("number")
-                        .short(str_as_char("n"))
+                        .short('n')
                         .help("Redo the last `n` migration files.")
                         .long_help(
                             "When this option is specified the last `n` migration files \
@@ -79,7 +77,7 @@ pub fn build_cli() -> Command<'static> {
                         )
                         .default_value("1")
                         .takes_value(true)
-                        .validator(is_positive_int)
+                        .value_parser(clap::value_parser!(u64))
                         .conflicts_with("REDO_ALL"),
                 ),
         )
@@ -111,10 +109,21 @@ pub fn build_cli() -> Command<'static> {
                         )
                         .takes_value(true),
                 )
+                .arg(
+                    Arg::new("MIGRATION_NO_DOWN_FILE")
+                        .short('u') // only Up
+                        .long("no-down")
+                        .help(
+                            "Don't generate a down.sql file. \
+                            You won't be able to run migration `revert` or `redo`.",
+                        )
+                        .takes_value(false),
+                )
                 .arg(
                     Arg::new("MIGRATION_FORMAT")
                         .long("format")
-                        .possible_values(&["sql", "barrel"])
+                        .value_parser(PossibleValuesParser::new(["sql"]))
+                        .takes_value(true)
                         .default_value("sql")
                         .takes_value(true)
                         .help("The format of the migration to be generated."),
@@ -154,7 +163,7 @@ pub fn build_cli() -> Command<'static> {
             Arg::new("SHELL")
                 .index(1)
                 .required(true)
-                .possible_values(Shell::possible_values()),
+                .value_parser(EnumValueParser::<Shell>::new()),
         );
 
     let infer_schema_subcommand = Command::new("print-schema")
@@ -162,7 +171,7 @@ pub fn build_cli() -> Command<'static> {
         .arg(
             Arg::new("schema")
                 .long("schema")
-                .short(str_as_char("s"))
+                .short('s')
                 .takes_value(true)
                 .help("The name of the schema."),
         )
@@ -171,19 +180,19 @@ pub fn build_cli() -> Command<'static> {
                 .index(1)
                 .takes_value(true)
                 .multiple_values(true)
-                .multiple_occurrences(true)
+                .action(clap::ArgAction::Append)
                 .help("Table names to filter (default only-tables if not empty)."),
         )
         .arg(
             Arg::new("only-tables")
-                .short(str_as_char("o"))
+                .short('o')
                 .long("only-tables")
                 .help("Only include tables from table-name that matches regexp.")
                 .conflicts_with("except-tables"),
         )
         .arg(
             Arg::new("except-tables")
-                .short(str_as_char("e"))
+                .short('e')
                 .long("except-tables")
                 .help("Exclude tables from table-name that matches regex.")
                 .conflicts_with("only-tables"),
@@ -198,12 +207,13 @@ pub fn build_cli() -> Command<'static> {
                 .long("column-sorting")
                 .help("Sort order for table columns.")
                 .takes_value(true)
-                .possible_values(&["ordinal_position", "name"]),
+                .value_parser(PossibleValuesParser::new(["ordinal_position", "name"])),
         )
         .arg(
             Arg::new("patch-file")
                 .long("patch-file")
                 .takes_value(true)
+                .value_parser(clap::value_parser!(std::path::PathBuf))
                 .help("A unified diff file to be applied to the final schema."),
         )
         .arg(
@@ -211,7 +221,7 @@ pub fn build_cli() -> Command<'static> {
                 .long("import-types")
                 .takes_value(true)
                 .multiple_values(true)
-                .multiple_occurrences(true)
+                .action(clap::ArgAction::Append)
                 .number_of_values(1)
                 .help("A list of types to import for every table, separated by commas."),
         )
@@ -222,6 +232,7 @@ pub fn build_cli() -> Command<'static> {
         );
 
     let config_arg = Arg::new("CONFIG_FILE")
+        .value_parser(clap::value_parser!(std::path::PathBuf))
         .long("config-file")
         .help(
             "The location of the configuration file to use. Falls back to the \
@@ -269,5 +280,6 @@ fn migration_dir_arg<'a>() -> Arg<'a> {
              current directory and its parents.",
         )
         .takes_value(true)
+        .value_parser(clap::value_parser!(std::path::PathBuf))
         .global(true)
 }
diff --git a/diesel_cli/src/config.rs b/diesel_cli/src/config.rs
index 8d97386b928b..0c4224fdf545 100644
--- a/diesel_cli/src/config.rs
+++ b/diesel_cli/src/config.rs
@@ -22,8 +22,8 @@ pub struct Config {
 impl Config {
     pub fn file_path(matches: &ArgMatches) -> PathBuf {
         matches
-            .value_of("CONFIG_FILE")
-            .map(PathBuf::from)
+            .get_one::<PathBuf>("CONFIG_FILE")
+            .cloned()
             .or_else(|| env::var_os("DIESEL_CONFIG_FILE").map(PathBuf::from))
             .unwrap_or_else(|| find_project_root().unwrap_or_default().join("diesel.toml"))
     }
diff --git a/diesel_cli/src/database.rs b/diesel_cli/src/database.rs
index ab5ab25be33e..c8f646328814 100644
--- a/diesel_cli/src/database.rs
+++ b/diesel_cli/src/database.rs
@@ -122,13 +122,6 @@ impl InferConnection {
 }
 
 macro_rules! call_with_conn {
-    (
-        $database_url:expr,
-        $($func:ident)::+
-    ) => {
-        call_with_conn!($database_url, $($func)::+ ())
-    };
-
     (
         $database_url:expr,
         $($func:ident)::+ ($($args:expr),*)
@@ -353,8 +346,8 @@ pub fn schema_table_exists(database_url: &str) -> DatabaseResult<bool> {
 
 pub fn database_url(matches: &ArgMatches) -> String {
     matches
-        .value_of("DATABASE_URL")
-        .map(|s| s.into())
+        .get_one::<String>("DATABASE_URL")
+        .cloned()
         .or_else(|| env::var("DATABASE_URL").ok())
         .unwrap_or_else(|| handle_error(DatabaseError::DatabaseUrlMissing))
 }
diff --git a/diesel_cli/src/infer_schema_internals/inference.rs b/diesel_cli/src/infer_schema_internals/inference.rs
index ae74e0147999..4b6b5da313ff 100644
--- a/diesel_cli/src/infer_schema_internals/inference.rs
+++ b/diesel_cli/src/infer_schema_internals/inference.rs
@@ -97,7 +97,7 @@ fn get_column_information(
         }
     };
     if let Err(NotFound) = column_info {
-        Err(format!("no table exists named {}", table.to_string()).into())
+        Err(format!("no table exists named {}", table).into())
     } else {
         column_info.map_err(Into::into)
     }
@@ -137,7 +137,7 @@ pub(crate) fn get_primary_keys(
         Err(format!(
             "Diesel only supports tables with primary keys. \
              Table {} has no primary key",
-            table.to_string()
+            table,
         )
         .into())
     } else {
diff --git a/diesel_cli/src/infer_schema_internals/information_schema.rs b/diesel_cli/src/infer_schema_internals/information_schema.rs
index cf4b2ef22503..aeff76e95627 100644
--- a/diesel_cli/src/infer_schema_internals/information_schema.rs
+++ b/diesel_cli/src/infer_schema_internals/information_schema.rs
@@ -2,9 +2,10 @@ use std::borrow::Cow;
 use std::error::Error;
 
 use diesel::backend::Backend;
+use diesel::connection::LoadConnection;
 use diesel::deserialize::{FromSql, FromSqlRow};
 use diesel::dsl::*;
-use diesel::expression::{is_aggregate, MixedAggregates, QueryMetadata, ValidGrouping};
+use diesel::expression::{is_aggregate, QueryMetadata, ValidGrouping};
 #[cfg(feature = "mysql")]
 use diesel::mysql::Mysql;
 #[cfg(feature = "postgres")]
@@ -36,7 +37,7 @@ pub trait UsesInformationSchema: Backend {
 
     fn default_schema<C>(conn: &mut C) -> QueryResult<String>
     where
-        C: Connection<Backend = Self>,
+        C: LoadConnection<Backend = Self>,
         String: FromSql<sql_types::Text, C::Backend>;
 }
 
@@ -76,7 +77,7 @@ impl UsesInformationSchema for Mysql {
 
     fn default_schema<C>(conn: &mut C) -> QueryResult<String>
     where
-        C: Connection<Backend = Self>,
+        C: LoadConnection<Backend = Self>,
         String: FromSql<sql_types::Text, C::Backend>,
     {
         select(database()).get_result(conn)
@@ -149,7 +150,7 @@ pub fn get_table_data<'a, Conn>(
     column_sorting: &ColumnSorting,
 ) -> QueryResult<Vec<ColumnInformation>>
 where
-    Conn: Connection,
+    Conn: LoadConnection,
     Conn::Backend: UsesInformationSchema,
     ColumnInformation: FromSqlRow<
         SqlTypeOf<(
@@ -160,10 +161,12 @@ where
         )>,
         Conn::Backend,
     >,
-    is_aggregate::No: MixedAggregates<
-        <<Conn::Backend as UsesInformationSchema>::TypeSchema as ValidGrouping<()>>::IsAggregate,
-        Output = is_aggregate::No,
-    >,
+    (
+        columns::column_name,
+        <Conn::Backend as UsesInformationSchema>::TypeColumn,
+        <Conn::Backend as UsesInformationSchema>::TypeSchema,
+        columns::__is_nullable,
+    ): ValidGrouping<()>,
     String: FromSql<sql_types::Text, Conn::Backend>,
     Option<String>: FromSql<sql_types::Nullable<sql_types::Text>, Conn::Backend>,
     Order<
@@ -230,7 +233,7 @@ where
 
 pub fn get_primary_keys<'a, Conn>(conn: &mut Conn, table: &'a TableName) -> QueryResult<Vec<String>>
 where
-    Conn: Connection,
+    Conn: LoadConnection,
     Conn::Backend: UsesInformationSchema,
     String: FromSql<sql_types::Text, Conn::Backend>,
     Order<
@@ -280,7 +283,7 @@ pub fn load_table_names<'a, Conn>(
     schema_name: Option<&'a str>,
 ) -> Result<Vec<TableName>, Box<dyn Error + Send + Sync + 'static>>
 where
-    Conn: Connection,
+    Conn: LoadConnection,
     Conn::Backend: UsesInformationSchema + 'static,
     String: FromSql<sql_types::Text, Conn::Backend>,
     Filter<
@@ -557,7 +560,7 @@ mod tests {
         let id = ColumnInformation::new("id", "int4", pg_catalog.clone(), false);
         let text_col = ColumnInformation::new("text_col", "varchar", pg_catalog.clone(), true);
         let not_null = ColumnInformation::new("not_null", "text", pg_catalog.clone(), false);
-        let array_col = ColumnInformation::new("array_col", "_varchar", pg_catalog.clone(), false);
+        let array_col = ColumnInformation::new("array_col", "_varchar", pg_catalog, false);
         assert_eq!(
             Ok(vec![id, text_col, not_null]),
             get_table_data(&mut connection, &table_1, &ColumnSorting::OrdinalPosition)
@@ -592,14 +595,14 @@ mod tests {
         let table_3 = TableName::new("table_3", "test_schema");
         let fk_one = ForeignKeyConstraint {
             child_table: table_2.clone(),
-            parent_table: table_1.clone(),
+            parent_table: table_1,
             foreign_key: "fk_one".into(),
             foreign_key_rust_name: "fk_one".into(),
             primary_key: "id".into(),
         };
         let fk_two = ForeignKeyConstraint {
-            child_table: table_3.clone(),
-            parent_table: table_2.clone(),
+            child_table: table_3,
+            parent_table: table_2,
             foreign_key: "fk_two".into(),
             foreign_key_rust_name: "fk_two".into(),
             primary_key: "id".into(),
diff --git a/diesel_cli/src/infer_schema_internals/sqlite.rs b/diesel_cli/src/infer_schema_internals/sqlite.rs
index 49e8636d9522..144cdd50393f 100644
--- a/diesel_cli/src/infer_schema_internals/sqlite.rs
+++ b/diesel_cli/src/infer_schema_internals/sqlite.rs
@@ -31,7 +31,7 @@ table! {
         seq -> Integer,
         _table -> VarChar,
         from -> VarChar,
-        to -> VarChar,
+        to -> Nullable<VarChar>,
         on_update -> VarChar,
         on_delete -> VarChar,
         _match -> VarChar,
@@ -71,20 +71,37 @@ pub fn load_foreign_key_constraints(
         .into_iter()
         .map(|child_table| {
             let query = format!("PRAGMA FOREIGN_KEY_LIST('{}')", child_table.sql_name);
-            Ok(sql::<pragma_foreign_key_list::SqlType>(&query)
+            sql::<pragma_foreign_key_list::SqlType>(&query)
                 .load::<ForeignKeyListRow>(connection)?
                 .into_iter()
                 .map(|row| {
                     let parent_table = TableName::from_name(row.parent_table);
-                    ForeignKeyConstraint {
+                    let primary_key = if let Some(primary_key) = row.primary_key {
+                        primary_key
+                    } else {
+                        let mut primary_keys = get_primary_keys(connection, &parent_table)?;
+                        if primary_keys.len() == 1 {
+                            primary_keys
+                                .pop()
+                                .expect("There is exactly one primary key in this list")
+                        } else {
+                            return Err(diesel::result::Error::DatabaseError(
+                                diesel::result::DatabaseErrorKind::Unknown,
+                                Box::new(String::from(
+                                    "Found more than one primary key for an implicit reference",
+                                )),
+                            ));
+                        }
+                    };
+                    Ok(ForeignKeyConstraint {
                         child_table: child_table.clone(),
                         parent_table,
                         foreign_key: row.foreign_key.clone(),
                         foreign_key_rust_name: row.foreign_key,
-                        primary_key: row.primary_key,
-                    }
+                        primary_key,
+                    })
                 })
-                .collect())
+                .collect::<Result<_, _>>()
         })
         .collect::<QueryResult<Vec<Vec<_>>>>()?;
     Ok(rows.into_iter().flatten().collect())
@@ -163,7 +180,7 @@ struct ForeignKeyListRow {
     _seq: i32,
     parent_table: String,
     foreign_key: String,
-    primary_key: String,
+    primary_key: Option<String>,
     _on_update: String,
     _on_delete: String,
     _match: String,
@@ -368,14 +385,14 @@ fn load_foreign_key_constraints_loads_foreign_keys() {
     let table_3 = TableName::from_name("table_3");
     let fk_one = ForeignKeyConstraint {
         child_table: table_2.clone(),
-        parent_table: table_1.clone(),
+        parent_table: table_1,
         foreign_key: "fk_one".into(),
         foreign_key_rust_name: "fk_one".into(),
         primary_key: "id".into(),
     };
     let fk_two = ForeignKeyConstraint {
-        child_table: table_3.clone(),
-        parent_table: table_2.clone(),
+        child_table: table_3,
+        parent_table: table_2,
         foreign_key: "fk_two".into(),
         foreign_key_rust_name: "fk_two".into(),
         primary_key: "id".into(),
diff --git a/diesel_cli/src/main.rs b/diesel_cli/src/main.rs
index 0e2346ddea21..1d0155551c7c 100644
--- a/diesel_cli/src/main.rs
+++ b/diesel_cli/src/main.rs
@@ -11,7 +11,7 @@
     clippy::used_underscore_binding,
     missing_copy_implementations
 )]
-#![cfg_attr(test, allow(clippy::result_unwrap_used))]
+#![cfg_attr(test, allow(clippy::unwrap_used))]
 
 mod config;
 
@@ -23,7 +23,6 @@ mod infer_schema_internals;
 mod print_schema;
 #[cfg(any(feature = "postgres", feature = "mysql"))]
 mod query_helper;
-mod validators;
 
 use chrono::*;
 use clap::ArgMatches;
@@ -76,27 +75,24 @@ fn run_migration_command(
             let database_url = database::database_url(matches);
             let dir = migrations_dir(matches).unwrap_or_else(handle_error);
             let dir = FileBasedMigrations::from_path(dir).unwrap_or_else(handle_error);
-            if args.is_present("REVERT_ALL") {
+            if args.contains_id("REVERT_ALL") {
                 call_with_conn!(database_url, revert_all_migrations_with_output(dir))?;
             } else {
-                let number = args.value_of("REVERT_NUMBER").unwrap();
-                for _ in 0..number.parse::<u64>().expect("Unable to parse the value of the --number argument. A positive integer is expected.") {
-                        match call_with_conn!(
-                            database_url,
-                            revert_migration_with_output(dir.clone())
-                        ) {
-                            Ok(_) => {}
-                            Err(e) if e.is::<MigrationError>() => {
-                                match e.downcast_ref::<MigrationError>() {
-                                    // If n is larger then the actual number of migrations,
-                                    // just stop reverting them
-                                    Some(MigrationError::NoMigrationRun) => break,
-                                    _ => return Err(e),
-                                }
+                let number = args.get_one::<u64>("REVERT_NUMBER").unwrap();
+                for _ in 0..*number {
+                    match call_with_conn!(database_url, revert_migration_with_output(dir.clone())) {
+                        Ok(_) => {}
+                        Err(e) if e.is::<MigrationError>() => {
+                            match e.downcast_ref::<MigrationError>() {
+                                // If n is larger then the actual number of migrations,
+                                // just stop reverting them
+                                Some(MigrationError::NoMigrationRun) => break,
+                                _ => return Err(e),
                             }
-                            Err(e) => return Err(e),
                         }
+                        Err(e) => return Err(e),
                     }
+                }
             }
 
             regenerate_schema_if_file_specified(matches)?;
@@ -123,7 +119,7 @@ fn run_migration_command(
             println!("{:?}", result);
         }
         ("generate", args) => {
-            let migration_name = args.value_of("MIGRATION_NAME").unwrap();
+            let migration_name = args.get_one::<String>("MIGRATION_NAME").unwrap();
             let version = migration_version(args);
             let versioned_name = format!("{}_{}", version, migration_name);
             let migration_dir = migrations_dir(matches)
@@ -131,8 +127,14 @@ fn run_migration_command(
                 .join(versioned_name);
             fs::create_dir(&migration_dir).unwrap();
 
-            match args.value_of("MIGRATION_FORMAT") {
-                Some("sql") => generate_sql_migration(&migration_dir),
+            match args
+                .get_one::<String>("MIGRATION_FORMAT")
+                .map(|s| s as &str)
+            {
+                Some("sql") => generate_sql_migration(
+                    &migration_dir,
+                    !args.contains_id("MIGRATION_NO_DOWN_FILE"),
+                ),
                 Some(x) => return Err(format!("Unrecognized migration format `{}`", x).into()),
                 None => unreachable!("MIGRATION_FORMAT has a default value"),
             }
@@ -143,7 +145,7 @@ fn run_migration_command(
     Ok(())
 }
 
-fn generate_sql_migration(path: &Path) {
+fn generate_sql_migration(path: &Path, with_down: bool) {
     use std::io::Write;
 
     let migration_dir_relative =
@@ -157,32 +159,31 @@ fn generate_sql_migration(path: &Path) {
     let mut up = fs::File::create(up_path).unwrap();
     up.write_all(b"-- Your SQL goes here").unwrap();
 
-    let down_path = path.join("down.sql");
-    println!(
-        "Creating {}",
-        migration_dir_relative.join("down.sql").display()
-    );
-    let mut down = fs::File::create(down_path).unwrap();
-    down.write_all(b"-- This file should undo anything in `up.sql`")
-        .unwrap();
+    if with_down {
+        let down_path = path.join("down.sql");
+        println!(
+            "Creating {}",
+            migration_dir_relative.join("down.sql").display()
+        );
+        let mut down = fs::File::create(down_path).unwrap();
+        down.write_all(b"-- This file should undo anything in `up.sql`")
+            .unwrap();
+    }
 }
 
 fn migration_version<'a>(matches: &'a ArgMatches) -> Box<dyn Display + 'a> {
     matches
-        .value_of("MIGRATION_VERSION")
+        .get_one::<String>("MIGRATION_VERSION")
         .map(|s| Box::new(s) as Box<dyn Display>)
         .unwrap_or_else(|| Box::new(Utc::now().format(TIMESTAMP_FORMAT)))
 }
 
 fn migrations_dir_from_cli(matches: &ArgMatches) -> Option<PathBuf> {
-    matches
-        .value_of("MIGRATION_DIRECTORY")
-        .map(PathBuf::from)
-        .or_else(|| {
-            matches
-                .subcommand()
-                .and_then(|s| migrations_dir_from_cli(s.1))
-        })
+    matches.get_one("MIGRATION_DIRECTORY").cloned().or_else(|| {
+        matches
+            .subcommand()
+            .and_then(|s| migrations_dir_from_cli(s.1))
+    })
 }
 
 fn run_migrations_with_output<Conn, DB>(
@@ -355,11 +356,10 @@ fn run_database_command(
 }
 
 fn generate_completions_command(matches: &ArgMatches) {
-    let shell: Shell = matches.value_of_t("SHELL").unwrap_or_else(|e| e.exit());
+    let shell: &Shell = matches.get_one("SHELL").expect("Shell is set here?");
     let mut app = cli::build_cli();
     let name = app.get_name().to_string();
-    generate(shell, &mut app, name, &mut stdout());
-    // cli::build_cli().gen_completions_to("diesel", shell, &mut stdout());
+    generate(*shell, &mut app, name, &mut stdout());
 }
 
 /// Looks for a migrations directory in the current path and all parent paths,
@@ -407,11 +407,11 @@ fn redo_migrations<Conn, DB>(
     Conn: MigrationHarness<DB> + Connection<Backend = DB> + 'static,
 {
     let migrations_inner = |harness: &mut HarnessWithOutput<Conn, _>| -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
-        let reverted_versions = if args.is_present("REDO_ALL") {
+        let reverted_versions = if args.contains_id("REDO_ALL") {
             harness.revert_all_migrations(migrations_dir.clone())?
         } else {
-            let number = args.value_of("REDO_NUMBER").unwrap();
-            (0..number.parse::<u64>().expect("Unable to parse the value of the --number argument. A positive integer is expected."))
+            let number = args.get_one::<u64>("REDO_NUMBER").unwrap();
+            (0..*number)
                 .filter_map(|_|{
                     match harness.revert_last_migration(migrations_dir.clone()) {
                         Ok(v) => {
@@ -438,7 +438,7 @@ fn redo_migrations<Conn, DB>(
             .map(|m| (m.name().version().as_owned(), m))
             .collect::<HashMap<_, _>>();
 
-        let migrations = reverted_versions
+        let mut migrations = reverted_versions
             .into_iter()
             .map(|v| {
                 migrations
@@ -446,6 +446,8 @@ fn redo_migrations<Conn, DB>(
                     .ok_or_else(|| MigrationError::UnknownMigrationVersion(v.as_owned()))
             })
             .collect::<Result<Vec<_>, _>>()?;
+        // Sort the migrations by version to apply them in order.
+        migrations.sort_by_key(|m| m.name().version().as_owned());
 
         harness.run_migrations(&migrations)?;
 
@@ -499,45 +501,45 @@ fn run_infer_schema(matches: &ArgMatches) -> Result<(), Box<dyn Error + Send + S
     let database_url = database::database_url(matches);
     let mut config = Config::read(matches)?.print_schema;
 
-    if let Some(schema_name) = matches.value_of("schema") {
-        config.schema = Some(String::from(schema_name))
+    if let Some(schema_name) = matches.get_one::<String>("schema") {
+        config.schema = Some(schema_name.clone())
     }
 
     let filter = matches
-        .values_of("table-name")
+        .get_many::<String>("table-name")
         .unwrap_or_default()
         .map(|table_name_regex| Regex::new(table_name_regex).map(Into::into))
         .collect::<Result<_, _>>()
         .map_err(|e| format!("invalid argument for table filtering regex: {}", e));
 
-    if matches.is_present("only-tables") {
+    if matches.contains_id("only-tables") {
         config.filter = Filtering::OnlyTables(filter?)
-    } else if matches.is_present("except-tables") {
+    } else if matches.contains_id("except-tables") {
         config.filter = Filtering::ExceptTables(filter?)
     }
 
-    if matches.is_present("with-docs") {
+    if matches.contains_id("with-docs") {
         config.with_docs = true;
     }
 
-    if let Some(sorting) = matches.value_of("column-sorting") {
-        match sorting {
+    if let Some(sorting) = matches.get_one::<String>("column-sorting") {
+        match sorting as &str {
             "ordinal_position" => config.column_sorting = ColumnSorting::OrdinalPosition,
             "name" => config.column_sorting = ColumnSorting::Name,
             _ => return Err(format!("Invalid column sorting mode: {}", sorting).into()),
         }
     }
 
-    if let Some(path) = matches.value_of("patch-file") {
-        config.patch_file = Some(PathBuf::from(path));
+    if let Some(path) = matches.get_one::<PathBuf>("patch-file") {
+        config.patch_file = Some(path.clone());
     }
 
-    if let Some(types) = matches.values_of("import-types") {
-        let types = types.map(String::from).collect();
+    if let Some(types) = matches.get_many("import-types") {
+        let types = types.cloned().collect();
         config.import_types = Some(types);
     }
 
-    if matches.is_present("generate-custom-type-definitions") {
+    if matches.contains_id("generate-custom-type-definitions") {
         config.generate_missing_sql_type_definitions = Some(false);
     }
 
@@ -558,7 +560,7 @@ fn regenerate_schema_if_file_specified(
 
         let database_url = database::database_url(matches);
 
-        if matches.is_present("LOCKED_SCHEMA") {
+        if matches.contains_id("LOCKED_SCHEMA") {
             let mut buf = Vec::new();
             print_schema::run_print_schema(&database_url, &config.print_schema, &mut buf)?;
 
diff --git a/diesel_cli/src/print_schema.rs b/diesel_cli/src/print_schema.rs
index a4b5a9694015..0e59f4846069 100644
--- a/diesel_cli/src/print_schema.rs
+++ b/diesel_cli/src/print_schema.rs
@@ -144,6 +144,8 @@ fn mysql_diesel_types() -> HashSet<&'static str> {
 
     types.insert("TinyInt");
     types.insert("Tinyint");
+    types.insert("Datetime");
+    types.insert("Json");
     types
 }
 
diff --git a/diesel_cli/src/validators/mod.rs b/diesel_cli/src/validators/mod.rs
deleted file mode 100644
index bed07382f7cc..000000000000
--- a/diesel_cli/src/validators/mod.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-pub(crate) mod num;
diff --git a/diesel_cli/src/validators/num.rs b/diesel_cli/src/validators/num.rs
deleted file mode 100644
index 941571a2d88f..000000000000
--- a/diesel_cli/src/validators/num.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-pub fn is_positive_int(val: &str) -> Result<(), String> {
-    match val.parse::<u64>() {
-        Ok(val) if val > 0 => Ok(()),
-        // If the the value is <= 0 or can't be parsed
-        _ => Err(format!("{} isn't a positive integer.", val)),
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::is_positive_int;
-
-    #[test]
-    fn is_positive_int_should_parse_a_positive_integer_from_input_string() {
-        assert_eq!(is_positive_int("1"), Ok(()))
-    }
-
-    #[test]
-    fn is_positive_int_should_throw_an_error_with_zero() {
-        assert_eq!(
-            is_positive_int("0"),
-            Err("0 isn't a positive integer.".to_string())
-        )
-    }
-
-    #[test]
-    fn is_positive_int_should_throw_an_error_with_negative_integer() {
-        assert_eq!(
-            is_positive_int("-5"),
-            Err("-5 isn't a positive integer.".to_string())
-        )
-    }
-
-    #[test]
-    fn is_positive_int_should_throw_an_error_with_float() {
-        assert_eq!(
-            is_positive_int("5.2"),
-            Err("5.2 isn't a positive integer.".to_string())
-        )
-    }
-}
diff --git a/diesel_derives/Cargo.toml b/diesel_derives/Cargo.toml
index c2bb216c676d..26d63418a0b5 100644
--- a/diesel_derives/Cargo.toml
+++ b/diesel_derives/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "diesel_derives"
-version = "2.0.0-rc.0"
+version = "2.0.0-rc.1"
 license = "MIT OR Apache-2.0"
 description = "You should not use this crate directly, it is internal to Diesel."
 documentation = "https://diesel.rs/guides/"
@@ -8,7 +8,7 @@ homepage = "https://diesel.rs"
 repository = "https://github.com/diesel-rs/diesel/tree/master/diesel_derives"
 autotests = false
 include = ["src/**/*", "LICENSE-*"]
-rust-version = "1.54.0"
+rust-version = "1.56.0"
 
 [dependencies]
 syn = { version = "1.0.73", features = ["derive", "fold"] }
@@ -21,7 +21,7 @@ cfg-if = "1"
 dotenvy = "0.15"
 
 [dev-dependencies.diesel]
-version = "~2.0.0-rc.0"
+version = "~2.0.0-rc.1"
 path = "../diesel"
 
 [lib]
diff --git a/diesel_derives/src/as_changeset.rs b/diesel_derives/src/as_changeset.rs
index a180bd96fbb3..0344f9c5e81b 100644
--- a/diesel_derives/src/as_changeset.rs
+++ b/diesel_derives/src/as_changeset.rs
@@ -33,10 +33,7 @@ pub fn derive(item: DeriveInput) -> TokenStream {
 
     let treat_none_as_null = model.treat_none_as_null();
 
-    let (_, ty_generics, where_clause) = item.generics.split_for_impl();
-    let mut impl_generics = item.generics.clone();
-    impl_generics.params.push(parse_quote!('update));
-    let (impl_generics, _, _) = impl_generics.split_for_impl();
+    let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
 
     let mut generate_borrowed_changeset = true;
 
@@ -106,6 +103,10 @@ pub fn derive(item: DeriveInput) -> TokenStream {
     };
 
     let changeset_borrowed = if generate_borrowed_changeset {
+        let mut impl_generics = item.generics.clone();
+        impl_generics.params.push(parse_quote!('update));
+        let (impl_generics, _, _) = impl_generics.split_for_impl();
+
         quote! {
             impl #impl_generics AsChangeset for &'update #struct_name #ty_generics
             #where_clause
diff --git a/diesel_derives/src/insertable.rs b/diesel_derives/src/insertable.rs
index 296a899743db..ac7e0d2b2a6d 100644
--- a/diesel_derives/src/insertable.rs
+++ b/diesel_derives/src/insertable.rs
@@ -1,9 +1,9 @@
-use proc_macro2::TokenStream;
-use syn::{DeriveInput, Expr, Path, Type};
-
 use attrs::AttributeSpanWrapper;
 use field::Field;
 use model::Model;
+use proc_macro2::TokenStream;
+use quote::quote_spanned;
+use syn::{DeriveInput, Expr, Path, Type};
 use util::{inner_of_option_ty, is_option_ty, wrap_in_dummy_mod};
 
 pub fn derive(item: DeriveInput) -> TokenStream {
@@ -13,10 +13,7 @@ pub fn derive(item: DeriveInput) -> TokenStream {
     let table_name = &model.table_name();
     let struct_name = &item.ident;
 
-    let (_, ty_generics, where_clause) = item.generics.split_for_impl();
-    let mut impl_generics = item.generics.clone();
-    impl_generics.params.push(parse_quote!('insert));
-    let (impl_generics, ..) = impl_generics.split_for_impl();
+    let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
 
     let mut generate_borrowed_insert = true;
 
@@ -90,13 +87,17 @@ pub fn derive(item: DeriveInput) -> TokenStream {
         {
             type Values = <(#(#direct_field_ty,)*) as Insertable<#table_name::table>>::Values;
 
-            fn values(self) -> Self::Values {
+            fn values(self) -> <(#(#direct_field_ty,)*) as Insertable<#table_name::table>>::Values {
                 (#(#direct_field_assign,)*).values()
             }
         }
     };
 
     let insert_borrowed = if generate_borrowed_insert {
+        let mut impl_generics = item.generics.clone();
+        impl_generics.params.push(parse_quote!('insert));
+        let (impl_generics, ..) = impl_generics.split_for_impl();
+
         quote! {
             impl #impl_generics Insertable<#table_name::table>
                 for &'insert #struct_name #ty_generics
@@ -104,7 +105,7 @@ pub fn derive(item: DeriveInput) -> TokenStream {
             {
                 type Values = <(#(#ref_field_ty,)*) as Insertable<#table_name::table>>::Values;
 
-                fn values(self) -> Self::Values {
+                fn values(self) -> <(#(#ref_field_ty,)*) as Insertable<#table_name::table>>::Values {
                     (#(#ref_field_assign,)*).values()
                 }
             }
@@ -132,13 +133,12 @@ pub fn derive(item: DeriveInput) -> TokenStream {
 
 fn field_ty_embed(field: &Field, lifetime: Option<TokenStream>) -> TokenStream {
     let field_ty = &field.ty;
-
-    quote!(#lifetime #field_ty)
+    let span = field.span;
+    quote_spanned!(span=> #lifetime #field_ty)
 }
 
 fn field_expr_embed(field: &Field, lifetime: Option<TokenStream>) -> TokenStream {
     let field_name = &field.name;
-
     quote!(#lifetime self.#field_name)
 }
 
@@ -149,23 +149,23 @@ fn field_ty_serialize_as(
     treat_none_as_default_value: bool,
 ) -> TokenStream {
     let column_name = field.column_name();
-
+    let span = field.span;
     if treat_none_as_default_value {
         let inner_ty = inner_of_option_ty(ty);
 
-        quote!(
+        quote_spanned! {span=>
             std::option::Option<diesel::dsl::Eq<
                 #table_name::#column_name,
                 #inner_ty,
             >>
-        )
+        }
     } else {
-        quote!(
+        quote_spanned! {span=>
             diesel::dsl::Eq<
                 #table_name::#column_name,
                 #ty,
             >
-        )
+        }
     }
 }
 
@@ -178,7 +178,6 @@ fn field_expr_serialize_as(
     let field_name = &field.name;
     let column_name = field.column_name();
     let column = quote!(#table_name::#column_name);
-
     if treat_none_as_default_value {
         if is_option_ty(ty) {
             quote!(self.#field_name.map(|x| #column.eq(::std::convert::Into::<#ty>::into(x))))
@@ -197,25 +196,25 @@ fn field_ty(
     treat_none_as_default_value: bool,
 ) -> TokenStream {
     let column_name = field.column_name();
-
+    let span = field.span;
     if treat_none_as_default_value {
         let inner_ty = inner_of_option_ty(&field.ty);
 
-        quote!(
+        quote_spanned! {span=>
             std::option::Option<diesel::dsl::Eq<
                 #table_name::#column_name,
                 #lifetime #inner_ty,
             >>
-        )
+        }
     } else {
         let inner_ty = &field.ty;
 
-        quote!(
+        quote_spanned! {span=>
             diesel::dsl::Eq<
                 #table_name::#column_name,
                 #lifetime #inner_ty,
             >
-        )
+        }
     }
 }
 
@@ -227,8 +226,8 @@ fn field_expr(
 ) -> TokenStream {
     let field_name = &field.name;
     let column_name = field.column_name();
-    let column: Expr = parse_quote!(#table_name::#column_name);
 
+    let column: Expr = parse_quote!(#table_name::#column_name);
     if treat_none_as_default_value {
         if is_option_ty(&field.ty) {
             if lifetime.is_some() {
diff --git a/diesel_dynamic_schema/Cargo.toml b/diesel_dynamic_schema/Cargo.toml
index 5f59deaa8257..438717eabb70 100644
--- a/diesel_dynamic_schema/Cargo.toml
+++ b/diesel_dynamic_schema/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "diesel-dynamic-schema"
-version = "0.2.0-rc.0"
+version = "0.2.0-rc.1"
 license = "MIT OR Apache-2.0"
 edition = "2018"
 autotests = false
@@ -11,9 +11,10 @@ repository = "https://github.com/diesel-rs/diesel"
 keywords = ["orm", "database", "sql"]
 categories = ["database"]
 include = ["src/**/*", "LICENSE-*", "README.md"]
+rust-version = "1.56.0"
 
 [dependencies.diesel]
-version = "~2.0.0-rc.0"
+version = "~2.0.0-rc.1"
 path = "../diesel/"
 default-features = false
 
diff --git a/diesel_migrations/Cargo.toml b/diesel_migrations/Cargo.toml
index dab04694edff..9780242dae0f 100644
--- a/diesel_migrations/Cargo.toml
+++ b/diesel_migrations/Cargo.toml
@@ -1,19 +1,19 @@
 [package]
 name = "diesel_migrations"
-version = "2.0.0-rc.0"
+version = "2.0.0-rc.1"
 license = "MIT OR Apache-2.0"
 description = "Migration management for diesel"
 documentation = "https://docs.rs/crate/diesel_migrations"
 homepage = "https://diesel.rs"
 edition = "2018"
-rust-version = "1.54.0"
+rust-version = "1.56.0"
 
 [dependencies.migrations_internals]
-version = "~2.0.0-rc.0"
+version = "~2.0.0-rc.1"
 path = "migrations_internals"
 
 [dependencies.migrations_macros]
-version = "~2.0.0-rc.0"
+version = "~2.0.0-rc.1"
 path = "migrations_macros"
 
 [dev-dependencies]
@@ -22,7 +22,7 @@ cfg-if = "1.0.0"
 tempfile = "3.2"
 
 [dependencies.diesel]
-version = "~2.0.0-rc.0"
+version = "~2.0.0-rc.1"
 path = "../diesel"
 default-features = false
 
diff --git a/diesel_migrations/migrations_internals/Cargo.toml b/diesel_migrations/migrations_internals/Cargo.toml
index 55080d199324..2a63ad5d1ec1 100644
--- a/diesel_migrations/migrations_internals/Cargo.toml
+++ b/diesel_migrations/migrations_internals/Cargo.toml
@@ -1,10 +1,10 @@
 [package]
 name = "migrations_internals"
-version = "2.0.0-rc.0"
+version = "2.0.0-rc.1"
 license = "MIT OR Apache-2.0"
 description = "Internal implementation of diesels migration mechanism"
 homepage = "https://diesel.rs"
-rust-version = "1.54.0"
+rust-version = "1.56.0"
 
 [dependencies]
 serde = {version = "1", features = ["derive"]}
diff --git a/diesel_migrations/migrations_internals/src/lib.rs b/diesel_migrations/migrations_internals/src/lib.rs
index 75165ebb8d4c..6ab5e98cb108 100644
--- a/diesel_migrations/migrations_internals/src/lib.rs
+++ b/diesel_migrations/migrations_internals/src/lib.rs
@@ -20,6 +20,7 @@
     missing_copy_implementations
 )]
 
+use std::ffi::OsString;
 use std::fs::{DirEntry, File};
 use std::io::Read;
 use std::path::{Path, PathBuf};
@@ -59,26 +60,23 @@ pub fn search_for_migrations_directory(path: &Path) -> Option<PathBuf> {
     if migration_path.is_dir() {
         Some(migration_path)
     } else {
-        path.parent()
-            .and_then(|p| search_for_migrations_directory(p))
+        path.parent().and_then(search_for_migrations_directory)
     }
 }
 
 pub fn valid_sql_migration_directory(path: &Path) -> bool {
-    file_names(path)
-        .map(|files| files.contains(&"down.sql".into()) && files.contains(&"up.sql".into()))
-        .unwrap_or(false)
+    file_names(path).map_or(false, |files| files.iter().any(|f| f == "up.sql"))
 }
 
 pub fn version_from_string(path: &str) -> Option<String> {
     path.split('_').next().map(|s| s.replace('-', ""))
 }
 
-pub fn file_names(path: &Path) -> Result<Vec<String>, std::io::Error> {
+fn file_names(path: &Path) -> Result<Vec<OsString>, std::io::Error> {
     path.read_dir()?
         .filter_map(|entry| match entry {
             Ok(entry) if entry.file_name().to_string_lossy().starts_with('.') => None,
-            Ok(entry) => Some(Ok(entry.file_name().to_string_lossy().into_owned())),
+            Ok(entry) => Some(Ok(entry.file_name())),
             Err(e) => Some(Err(e)),
         })
         .collect::<Result<Vec<_>, _>>()
diff --git a/diesel_migrations/migrations_macros/Cargo.toml b/diesel_migrations/migrations_macros/Cargo.toml
index 68509fa19246..e3ae76eb2bd0 100644
--- a/diesel_migrations/migrations_macros/Cargo.toml
+++ b/diesel_migrations/migrations_macros/Cargo.toml
@@ -1,18 +1,18 @@
 [package]
 name = "migrations_macros"
-version = "2.0.0-rc.0"
+version = "2.0.0-rc.1"
 license = "MIT OR Apache-2.0"
 description = "Codegeneration macros for diesels embedded migrations"
 homepage = "https://diesel.rs"
 edition = "2018"
-rust-version = "1.54.0"
+rust-version = "1.56.0"
 
 [dependencies]
 quote = "1"
 proc-macro2 = "1"
 
 [dependencies.migrations_internals]
-version = "~2.0.0-rc.0"
+version = "~2.0.0-rc.1"
 path = "../migrations_internals"
 
 [dev-dependencies]
@@ -21,12 +21,12 @@ dotenvy = "0.15"
 cfg-if = "1.0.0"
 
 [dev-dependencies.diesel]
-version = "~2.0.0-rc.0"
+version = "~2.0.0-rc.1"
 path = "../../diesel"
 default-features = false
 
 [dev-dependencies.diesel_migrations]
-version = "~2.0.0-rc.0"
+version = "~2.0.0-rc.1"
 path = "../"
 default-features = false
 
diff --git a/diesel_migrations/migrations_macros/src/embed_migrations.rs b/diesel_migrations/migrations_macros/src/embed_migrations.rs
index 6f7d77db38e7..5a887ae2c68b 100644
--- a/diesel_migrations/migrations_macros/src/embed_migrations.rs
+++ b/diesel_migrations/migrations_macros/src/embed_migrations.rs
@@ -9,7 +9,7 @@ pub fn expand(path: String) -> proc_macro2::TokenStream {
     let migrations_path_opt = if path.is_empty() {
         None
     } else {
-        Some(path.replace("\"", ""))
+        Some(path.replace('"', ""))
     };
     let migrations_expr = migration_directory_from_given_path(migrations_path_opt.as_deref())
         .unwrap_or_else(|_| {
@@ -46,21 +46,28 @@ fn migration_literal_from_path(path: &Path) -> proc_macro2::TokenStream {
         .to_string_lossy();
     if version_from_string(&name).is_none() {
         panic!(
-            "Invalid migration directory, the directory's name should be \
-             <timestamp>_<name_of_migration>, and it should only contain \
-             up.sql and down.sql."
+            "Invalid migration directory: the directory's name should be \
+             <timestamp>_<name_of_migration>, and it should contain \
+             up.sql and optionally down.sql."
         );
     }
-    let up_sql = path.join("up.sql");
-    let up_sql_path = up_sql.to_str();
-    let down_sql = path.join("down.sql");
-    let down_sql_path = down_sql.to_str();
+    let up_sql_path = path.join("up.sql");
+    let up_sql_path = up_sql_path.to_str();
+    let down_sql_path = path.join("down.sql");
     let metadata = TomlMetadata::read_from_file(&path.join("metadata.toml")).unwrap_or_default();
     let run_in_transaction = metadata.run_in_transaction;
 
+    let down_sql = match down_sql_path.metadata() {
+        Err(e) if e.kind() == std::io::ErrorKind::NotFound => quote! { None },
+        _ => {
+            let down_sql_path = down_sql_path.to_str();
+            quote! { Some(include_str!(#down_sql_path)) }
+        }
+    };
+
     quote!(diesel_migrations::EmbeddedMigration::new(
         include_str!(#up_sql_path),
-        include_str!(#down_sql_path),
+        #down_sql,
         diesel_migrations::EmbeddedName::new(#name),
         diesel_migrations::TomlMetadataWrapper::new(#run_in_transaction)
     ))
diff --git a/diesel_migrations/migrations_macros/src/lib.rs b/diesel_migrations/migrations_macros/src/lib.rs
index 7a0223d1acff..2e1495fe1b1a 100644
--- a/diesel_migrations/migrations_macros/src/lib.rs
+++ b/diesel_migrations/migrations_macros/src/lib.rs
@@ -20,7 +20,7 @@
     missing_debug_implementations,
     missing_copy_implementations
 )]
-#![cfg_attr(test, allow(clippy::option_unwrap_used, clippy::result_unwrap_used))]
+#![cfg_attr(test, allow(clippy::unwrap_used))]
 extern crate proc_macro;
 
 mod embed_migrations;
@@ -95,6 +95,24 @@ use proc_macro::TokenStream;
 ///     Ok(())
 /// }
 /// ```
+///
+/// # Automatic rebuilds
+///
+/// Due to limitations in rusts proc-macro API there is currently no
+/// way to signal that a specific proc macro should be rerun if some
+/// external file changes/is added. This implies that `embed_migrations!`
+/// cannot regenerate the list of embedded migrations if **only** the
+/// migrations are changed. This limitation can be solved by adding a
+/// custom `build.rs` file to your crate, such that the crate is rebuild
+/// if the migration directory changes.
+///
+/// Add the following `build.rs` file to your project to fix the problem
+///
+/// ```
+/// fn main() {
+///    println!("cargo:rerun-if-changed=path/to/your/migration/dir/relative/to/your/Cargo.toml");
+/// }
+/// ```
 #[proc_macro]
 pub fn embed_migrations(input: TokenStream) -> TokenStream {
     embed_migrations::expand(input.to_string())
diff --git a/diesel_migrations/src/embedded_migrations.rs b/diesel_migrations/src/embedded_migrations.rs
index b2e7f10dfd4b..3c8d540d07ae 100644
--- a/diesel_migrations/src/embedded_migrations.rs
+++ b/diesel_migrations/src/embedded_migrations.rs
@@ -2,6 +2,7 @@ use std::fmt::Display;
 
 use crate::errors::RunMigrationsError;
 use crate::file_based_migrations::{DieselMigrationName, TomlMetadataWrapper};
+use crate::MigrationError;
 use diesel::backend::Backend;
 use diesel::migration::{Migration, MigrationName, MigrationSource, MigrationVersion, Result};
 
@@ -34,7 +35,7 @@ impl<DB: Backend> MigrationSource<DB> for EmbeddedMigrations {
 #[doc(hidden)]
 pub struct EmbeddedMigration {
     up: &'static str,
-    down: &'static str,
+    down: Option<&'static str>,
     name: EmbeddedName,
     metadata: TomlMetadataWrapper,
 }
@@ -43,7 +44,7 @@ impl EmbeddedMigration {
     #[doc(hidden)]
     pub const fn new(
         up: &'static str,
-        down: &'static str,
+        down: Option<&'static str>,
         name: EmbeddedName,
         metadata: TomlMetadataWrapper,
     ) -> Self {
@@ -95,11 +96,14 @@ impl<'a, DB: Backend> Migration<DB> for &'a EmbeddedMigration {
     }
 
     fn revert(&self, conn: &mut dyn diesel::connection::BoxableConnection<DB>) -> Result<()> {
-        Ok(conn.batch_execute(self.down).map_err(|e| {
-            let name = DieselMigrationName::from_name(self.name.name)
-                .expect("We have a vaild name here, we checked this in `embed_migration!`");
-            RunMigrationsError::QueryError(name, e)
-        })?)
+        match self.down {
+            Some(down) => Ok(conn.batch_execute(down).map_err(|e| {
+                let name = DieselMigrationName::from_name(self.name.name)
+                    .expect("We have a vaild name here, we checked this in `embed_migration!`");
+                RunMigrationsError::QueryError(name, e)
+            })?),
+            None => Err(MigrationError::NoMigrationRevertFile.into()),
+        }
     }
 
     fn metadata(&self) -> &dyn diesel::migration::MigrationMetadata {
diff --git a/diesel_migrations/src/errors.rs b/diesel_migrations/src/errors.rs
index 06c372eb3c86..f85894cc76e6 100644
--- a/diesel_migrations/src/errors.rs
+++ b/diesel_migrations/src/errors.rs
@@ -25,6 +25,9 @@ pub enum MigrationError {
     UnknownMigrationVersion(MigrationVersion<'static>),
     /// No migrations had to be/ could be run
     NoMigrationRun,
+    /// `down.sql` file is missing, and you're asking for a `revert`
+    /// or `redo`
+    NoMigrationRevertFile,
 }
 
 impl Error for MigrationError {}
@@ -39,8 +42,9 @@ impl fmt::Display for MigrationError {
             ),
             MigrationError::UnknownMigrationFormat(_) => write!(
                 f,
-                "Invalid migration directory, the directory's name should be \
-                 <timestamp>_<name_of_migration>, and it should only contain up.sql and down.sql."
+                "Invalid migration directory: the directory's name should be \
+                 <timestamp>_<name_of_migration>, and it should contain up.sql and \
+                 optionally down.sql."
             ),
             MigrationError::IoError(ref error) => write!(f, "{}", error),
             MigrationError::UnknownMigrationVersion(ref version) => write!(
@@ -52,6 +56,9 @@ impl fmt::Display for MigrationError {
                 f,
                 "No migrations have been run. Did you forget `diesel migration run`?"
             ),
+            MigrationError::NoMigrationRevertFile => {
+                write!(f, "Missing `down.sql` file to revert migration")
+            }
         }
     }
 }
diff --git a/diesel_migrations/src/file_based_migrations.rs b/diesel_migrations/src/file_based_migrations.rs
index 6fbb653de6bd..2aa5c1df78d6 100644
--- a/diesel_migrations/src/file_based_migrations.rs
+++ b/diesel_migrations/src/file_based_migrations.rs
@@ -185,11 +185,12 @@ impl<DB: Backend> Migration<DB> for SqlFileMigration {
     }
 
     fn revert(&self, conn: &mut dyn BoxableConnection<DB>) -> migration::Result<()> {
-        Ok(run_sql_from_file(
-            conn,
-            &self.base_path.join("down.sql"),
-            &self.name,
-        )?)
+        let down_path = self.base_path.join("down.sql");
+        if matches!(down_path.metadata(), Err(e) if e.kind() == std::io::ErrorKind::NotFound) {
+            Err(MigrationError::NoMigrationRevertFile.into())
+        } else {
+            Ok(run_sql_from_file(conn, &down_path, &self.name)?)
+        }
     }
 
     fn metadata(&self) -> &dyn MigrationMetadata {
diff --git a/examples/mysql/all_about_inserts/Cargo.toml b/examples/mysql/all_about_inserts/Cargo.toml
index ece84c395e1d..8611e4be8b4e 100644
--- a/examples/mysql/all_about_inserts/Cargo.toml
+++ b/examples/mysql/all_about_inserts/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["mysql", "chrono"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["mysql", "chrono"] }
 serde = { version = "1.0.130", features = ["derive"] }
 serde_json = "1.0.68"
 chrono = { version = "0.4.19", default-features = false, features = ["clock", "std"] }
diff --git a/examples/mysql/all_about_inserts/src/lib.rs b/examples/mysql/all_about_inserts/src/lib.rs
index f00d6d11a7b7..39ba19f7cd89 100644
--- a/examples/mysql/all_about_inserts/src/lib.rs
+++ b/examples/mysql/all_about_inserts/src/lib.rs
@@ -258,24 +258,24 @@ fn insert_get_results_batch() {
     use diesel::result::Error;
 
     let conn = &mut establish_connection();
-    conn.test_transaction::<_, Error, _>(|| {
+    conn.test_transaction::<_, Error, _>(|conn| {
         use diesel::select;
         use schema::users::dsl::*;
 
-        let now = select(diesel::dsl::now).get_result::<NaiveDateTime>(&conn)?;
+        let now = select(diesel::dsl::now).get_result::<NaiveDateTime>(conn)?;
 
-        let inserted_users = conn.transaction::<_, Error, _>(|| {
+        let inserted_users = conn.transaction::<_, Error, _>(|conn| {
             let inserted_count = insert_into(users)
                 .values(&vec![
                     (id.eq(1), name.eq("Sean")),
                     (id.eq(2), name.eq("Tess")),
                 ])
-                .execute(&conn)?;
+                .execute(conn)?;
 
             Ok(users
                 .order(id.desc())
                 .limit(inserted_count as i64)
-                .load(&conn)?
+                .load(conn)?
                 .into_iter()
                 .rev()
                 .collect::<Vec<_>>())
@@ -330,18 +330,18 @@ fn insert_get_result() {
     use diesel::result::Error;
 
     let conn = &mut establish_connection();
-    conn.test_transaction::<_, Error, _>(|| {
+    conn.test_transaction::<_, Error, _>(|conn| {
         use diesel::select;
         use schema::users::dsl::*;
 
-        let now = select(diesel::dsl::now).get_result::<NaiveDateTime>(&conn)?;
+        let now = select(diesel::dsl::now).get_result::<NaiveDateTime>(conn)?;
 
-        let inserted_user = conn.transaction::<_, Error, _>(|| {
+        let inserted_user = conn.transaction::<_, Error, _>(|conn| {
             insert_into(users)
                 .values((id.eq(3), name.eq("Ruby")))
-                .execute(&conn)?;
+                .execute(conn)?;
 
-            users.order(id.desc()).first(&conn)
+            users.order(id.desc()).first(conn)
         })?;
 
         let expected_user = User {
diff --git a/examples/mysql/getting_started_step_1/Cargo.toml b/examples/mysql/getting_started_step_1/Cargo.toml
index 5571eeae3e63..63c718d25cf2 100644
--- a/examples/mysql/getting_started_step_1/Cargo.toml
+++ b/examples/mysql/getting_started_step_1/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["mysql"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["mysql"] }
 dotenvy = "0.15"
 
 [[bin]]
diff --git a/examples/mysql/getting_started_step_2/Cargo.toml b/examples/mysql/getting_started_step_2/Cargo.toml
index de5ac30f5016..bbb3c0934d0f 100644
--- a/examples/mysql/getting_started_step_2/Cargo.toml
+++ b/examples/mysql/getting_started_step_2/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["mysql"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["mysql"] }
 dotenvy = "0.15"
 
 [[bin]]
diff --git a/examples/mysql/getting_started_step_3/Cargo.toml b/examples/mysql/getting_started_step_3/Cargo.toml
index d6c5e8f55e9d..9ca8a7ff059c 100644
--- a/examples/mysql/getting_started_step_3/Cargo.toml
+++ b/examples/mysql/getting_started_step_3/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["mysql"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["mysql"] }
 dotenvy = "0.15"
 
 [[bin]]
diff --git a/examples/postgres/advanced-blog-cli/Cargo.toml b/examples/postgres/advanced-blog-cli/Cargo.toml
index 72b26016bc8f..13d4810ae164 100644
--- a/examples/postgres/advanced-blog-cli/Cargo.toml
+++ b/examples/postgres/advanced-blog-cli/Cargo.toml
@@ -6,14 +6,14 @@ edition = "2018"
 [dependencies]
 bcrypt = "0.10.1"
 chrono = { version = "0.4.19", default-features = false, features = ["clock", "std"] }
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["postgres", "chrono"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["postgres", "chrono"] }
 dotenvy = "0.15"
 structopt = "0.3"
 tempfile = "3.1.0"
 
 [dev-dependencies]
 assert_matches = "1.1"
-diesel_migrations = { version = "2.0.0-rc.0", features = ["postgres"], path = "../../../diesel_migrations" }
+diesel_migrations = { version = "2.0.0-rc.1", features = ["postgres"], path = "../../../diesel_migrations" }
 lazy_static = "1.0"
 
 [[bin]]
diff --git a/examples/postgres/all_about_inserts/Cargo.toml b/examples/postgres/all_about_inserts/Cargo.toml
index 149385a7b8e3..2314c79859aa 100644
--- a/examples/postgres/all_about_inserts/Cargo.toml
+++ b/examples/postgres/all_about_inserts/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["postgres"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["postgres"] }
 serde = { version = "1.0.130", features = ["derive"] }
 serde_json = "1.0.68"
 
diff --git a/examples/postgres/all_about_updates/Cargo.toml b/examples/postgres/all_about_updates/Cargo.toml
index ce3a34f34d04..f48c952f51fb 100644
--- a/examples/postgres/all_about_updates/Cargo.toml
+++ b/examples/postgres/all_about_updates/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["postgres"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["postgres"] }
 
 [lib]
 doc = false
diff --git a/examples/postgres/custom_types/Cargo.toml b/examples/postgres/custom_types/Cargo.toml
index da916239ad0d..ee8a2104711f 100644
--- a/examples/postgres/custom_types/Cargo.toml
+++ b/examples/postgres/custom_types/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
-diesel = { path = "../../../diesel", version = "2.0.0-rc.0", features = ["postgres"] }
+diesel = { path = "../../../diesel", version = "2.0.0-rc.1", features = ["postgres"] }
 
 [[bin]]
 name = "custom-types"
diff --git a/examples/postgres/getting_started_step_1/Cargo.toml b/examples/postgres/getting_started_step_1/Cargo.toml
index 4e49cbf2b8b3..36ecf2524226 100644
--- a/examples/postgres/getting_started_step_1/Cargo.toml
+++ b/examples/postgres/getting_started_step_1/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["postgres"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["postgres"] }
 dotenvy = "0.15"
 
 [[bin]]
diff --git a/examples/postgres/getting_started_step_2/Cargo.toml b/examples/postgres/getting_started_step_2/Cargo.toml
index 3d53a3a10348..67fb736aee96 100644
--- a/examples/postgres/getting_started_step_2/Cargo.toml
+++ b/examples/postgres/getting_started_step_2/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["postgres"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["postgres"] }
 dotenvy = "0.15"
 
 [[bin]]
diff --git a/examples/postgres/getting_started_step_3/Cargo.toml b/examples/postgres/getting_started_step_3/Cargo.toml
index be6aea7c76a9..d585af312688 100644
--- a/examples/postgres/getting_started_step_3/Cargo.toml
+++ b/examples/postgres/getting_started_step_3/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["postgres"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["postgres"] }
 dotenvy = "0.15"
 
 [[bin]]
diff --git a/examples/sqlite/all_about_inserts/Cargo.toml b/examples/sqlite/all_about_inserts/Cargo.toml
index 6b1c8a281c85..8598b3ae89cc 100644
--- a/examples/sqlite/all_about_inserts/Cargo.toml
+++ b/examples/sqlite/all_about_inserts/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["sqlite", "chrono"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["sqlite", "chrono"] }
 serde = { version = "1.0.130", features = ["derive"] }
 serde_json = "1.0.68"
 chrono = { version = "0.4.19", default-features = false, features = ["clock", "std"] }
diff --git a/examples/sqlite/all_about_inserts/src/lib.rs b/examples/sqlite/all_about_inserts/src/lib.rs
index 78b23447cc6d..3a29eef3ae68 100644
--- a/examples/sqlite/all_about_inserts/src/lib.rs
+++ b/examples/sqlite/all_about_inserts/src/lib.rs
@@ -273,24 +273,24 @@ fn insert_get_results_batch() {
     use diesel::result::Error;
 
     let conn = &mut establish_connection();
-    conn.test_transaction::<_, Error, _>(|| {
+    conn.test_transaction::<_, Error, _>(|conn| {
         use diesel::select;
         use schema::users::dsl::*;
 
-        let now = select(diesel::dsl::now).get_result::<NaiveDateTime>(&conn)?;
+        let now = select(diesel::dsl::now).get_result::<NaiveDateTime>(conn)?;
 
-        let inserted_users = conn.transaction::<_, Error, _>(|| {
+        let inserted_users = conn.transaction::<_, Error, _>(|conn| {
             let inserted_count = insert_into(users)
                 .values(&vec![
                     (id.eq(1), name.eq("Sean")),
                     (id.eq(2), name.eq("Tess")),
                 ])
-                .execute(&conn)?;
+                .execute(conn)?;
 
             Ok(users
                 .order(id.desc())
                 .limit(inserted_count as i64)
-                .load(&conn)?
+                .load(conn)?
                 .into_iter()
                 .rev()
                 .collect::<Vec<_>>())
@@ -346,13 +346,13 @@ fn examine_sql_from_insert_get_results_batch() {
 //     use diesel::result::Error;
 
 //     let conn = &mut establish_connection();
-//     conn.test_transaction::<_, Error, _>(|| {
+//     conn.test_transaction::<_, Error, _>(|conn| {
 //         use diesel::select;
 //         use schema::users::dsl::*;
 
 //         let now = select(diesel::dsl::now).get_result::<NaiveDateTime>(&conn)?;
 
-//         let inserted_user = conn.transaction::<_, Error, _>(|| {
+//         let inserted_user = conn.transaction::<_, Error, _>(|conn| {
 //             insert_into(users)
 //                 .values((id.eq(3), name.eq("Ruby")))
 //                 .execute(&conn)?;
diff --git a/examples/sqlite/getting_started_step_1/Cargo.toml b/examples/sqlite/getting_started_step_1/Cargo.toml
index c8b5837edc4b..113039dddace 100644
--- a/examples/sqlite/getting_started_step_1/Cargo.toml
+++ b/examples/sqlite/getting_started_step_1/Cargo.toml
@@ -6,7 +6,7 @@ authors = ["Taryn Hill <taryn@phrohdoh.com>"]
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["sqlite"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["sqlite"] }
 dotenvy = "0.15"
 
 [[bin]]
diff --git a/examples/sqlite/getting_started_step_2/Cargo.toml b/examples/sqlite/getting_started_step_2/Cargo.toml
index 37076027ebdb..04dd56514893 100644
--- a/examples/sqlite/getting_started_step_2/Cargo.toml
+++ b/examples/sqlite/getting_started_step_2/Cargo.toml
@@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["sqlite"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["sqlite"] }
 dotenvy = "0.15"
 
 [[bin]]
diff --git a/examples/sqlite/getting_started_step_3/Cargo.toml b/examples/sqlite/getting_started_step_3/Cargo.toml
index 948f3837f377..553fa0741cfd 100644
--- a/examples/sqlite/getting_started_step_3/Cargo.toml
+++ b/examples/sqlite/getting_started_step_3/Cargo.toml
@@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0"
 edition = "2018"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", path = "../../../diesel", features = ["sqlite"] }
+diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["sqlite"] }
 dotenvy = "0.15"
 
 [[bin]]
diff --git a/guide_drafts/migration_guide.md b/guide_drafts/migration_guide.md
index 1fe1e8c2df02..24418630c1ff 100644
--- a/guide_drafts/migration_guide.md
+++ b/guide_drafts/migration_guide.md
@@ -9,39 +9,43 @@ are marked as deprecated in Diesel 1.4.x.
 Any code base using migrating to Diesel 2.0 is expected to be affected at least by 
 the following changes:
 
-* [Diesel now requires a mutable reference to the connection](2-0-0-mutable-connection)
-* [Changed derive attributes](2-0-0-derive-attributes)
+* [Diesel now requires a mutable reference to the connection](#2-0-0-mutable-connection)
+* [Changed derive attributes](#2-0-0-derive-attributes)
 
 Users of `diesel_migration` are additionally affected by the following change:
 
-* [`diesel_migration` rewrite](2-0-0-upgrade-migrations)
+* [`diesel_migration` rewrite](#2-0-0-upgrade-migrations)
 
 Users of `BoxableExpression` might be affected by the following change:
 
-* [Changed nullability of operators](2-0-0-nullability-ops)
+* [Changed nullability of operators](#2-0-0-nullability-ops)
+
+Users of tables containing a column of the type `Array<T>` are affected by the following change:
+
+* [Changed nullability of array elemetns](#2-0-0-nullability-of-array-elements)
 
 Users that implement support for their SQL types or type mappings are affected 
 by the following changes:
 
-* [Changed required traits for custom SQL types](2-0-0-custom-type-implementation)
-* [Changed `ToSql` implementations](2-0-0-to-sql)
-* [Changed `FromSql` implementations](2-0-0-from-sql)
+* [Changed required traits for custom SQL types](#2-0-0-custom-type-implementation)
+* [Changed `ToSql` implementations](#2-0-0-to-sql)
+* [Changed `FromSql` implementations](#2-0-0-from-sql)
 
 `no_arg_sql_function!` macro is now pending deprecation.
 Users of the macro are advised to consider `sql_function!` macro.
 
-* [Deprecated usage of `no_arg_sql_function!` macro](2-0-0-no_arg_sql_function)
+* [Deprecated usage of `no_arg_sql_function!` macro](#2-0-0-no_arg_sql_function)
 
 Users that update generic Diesel code will also be affected by the following changes:
 
-* [Removing `NonAggregate` in favor of `ValidGrouping`](2-0-0-upgrade-non-aggregate)
-* [Changed generic bounds](2-0-0-generic-changes)
+* [Removing `NonAggregate` in favor of `ValidGrouping`](#2-0-0-upgrade-non-aggregate)
+* [Changed generic bounds](#2-0-0-generic-changes)
 
 Additionally this release contains many changes for users that implemented a custom backend/connection.
 We do not provide explicit migration steps but we encourage users to reach out with questions pertaining to these changes. 
 
-## Mutable Connections required
-<a name="2-0-0-mutable-connection"></a>
+
+## Mutable Connections required<a name="2-0-0-mutable-connection"></a>
 
 Diesel now requires mutable access to the `Connection` to perform any database interaction. The following changes
 are required for all usages of any `Connection` type:
@@ -56,8 +60,7 @@ are required for all usages of any `Connection` type:
 We expect this to be a straightforward change as the connection already can execute only one query at a time.
 
 
-## Derive attributes
-<a name="2-0-0-derive-attributes"></a>
+## Derive attributes<a name="2-0-0-derive-attributes"></a>
 
 We have updated all of our Diesel derive attributes to follow the patterns that are used
 widely in the Rust's ecosystem. This means that all of them need to be wrapped by `#[diesel()]` now.  You can now specify multiple attributes on the same line using `,` separator.
@@ -66,8 +69,7 @@ This is backward compatible and thus all of your old attributes will still work,
 warnings. The attributes can be upgraded by either looking at the warnings or by reading
 diesel derive documentation reference.
 
-## `diesel_migration` rewrite
-<a name = "2-0-0-upgrade-migrations"></a>
+## `diesel_migration` rewrite<a name = "2-0-0-upgrade-migrations"></a>
 
 We have completely rewritten the `diesel_migration` crate. As a part of this rewrite all 
 free standing functions are removed from `diesel_migration`. Equivalent functionality 
@@ -102,8 +104,7 @@ fn run_migration(conn: &PgConnection) {
 }
 ```
 
-## Changed nullability of operators
-<a name="2-0-0-nullability-ops"></a>
+## Changed nullability of operators<a name="2-0-0-nullability-ops"></a>
 
 We changed the way how we handle the propagation of null values through binary operators. Diesel 1.x always assumed 
 that the result of a binary operation `value_a > value_b` is not nullable, which does not match the behaviour of the 
@@ -113,10 +114,19 @@ of `BoxableExpression` as it may change the resulting sql type there. As a possi
 there we recommend to use one of the following functions:
 
 * `NullableExpressionMethods::nullable()`
-* `NullableExpressionMethods::assume_not_nullable()`
+* `NullableExpressionMethods::assume_not_null()`
+
+## Changed nullability of array elements<a name="#2-0-0-nullability-of-array-elements"></a>
+
+We changed the inferred SQL type for columns with array types for the PostgreSQL backend. Instead of using `Array<ST>` 
+we now infer `Array<Nullable<ST>>` to support arrays containing `NULL` values. This change implies a change mapping
+of columns of the corresponding types. It is possible to handle this change using one of the following strategies:
+
+* Use `Vec<Option<T>>` as rust side type instead of `Vec<T>`
+* Manually set the corresponding column to `Array<ST>` in your schema, to signal that this array does not contain null values. You may want to use the `patch_file` key for diesel CLI for this.
+* Use `#[diesel(deserialize_as = "…")]` to explicitly overwrite the  deserialization implementation used for this specific struct field. Checkout the documentation of `#[derive(Queryable)]` for details.
 
-## Custom SQL type implementations
-<a name="2-0-0-custom-type-implementation"></a>
+## Custom SQL type implementations<a name="2-0-0-custom-type-implementation"></a>
 
 We changed how we mark sql types as nullable at type level. For this we replaced the `NonNull` trait with a 
 more generic `SqlType` trait, which allows to mark a sql type as (non-) nullable. This may affect custom
@@ -137,7 +147,7 @@ Additionally, the diesel CLI tool was changed so that it automatically generates
 as long as they appear on any table. This feature currently only supports the PostgreSQL backend, as all other supported backends
 do not support real custom types at SQL level at all.
 
-## Changed `ToSql` implementations
+## Changed `ToSql` implementations<a name="2-0-0-to-sql"></a>
 
 We restructured the way Diesel serializes Rust values to their backend specific representation.
 This enables us to skip copying the value at all if the specific backend supports writing to a 
@@ -155,8 +165,7 @@ For backend concrete implementations, the following functions allow You to work
 
 
 
-## Changed `FromSql` implementations
-<a name="2-0-0-from-sql"></a>
+## Changed `FromSql` implementations<a name="2-0-0-from-sql"></a>
 
 We changed the raw value representation for both PostgreSQL and MySQL
 backends, from a `& [u8]` to an opaque type. This allows us to include additional information like the database side
@@ -168,7 +177,7 @@ Any affected backend needs to perform the following changes:
 ```diff
 impl<DB: Backend> FromSql<YourSqlType, DB> for YourType {
 -    fn from_sql(bytes: &[u8]) -> deserialize::Result<Self> {
-+    fn from_sql(value: backend::RawValue<DB>) -> deserialize::Result<Self> {
++    fn from_sql(value: backend::RawValue<'_, DB>) -> deserialize::Result<Self> {
 +        let bytes = value.as_bytes();
          // …
      }
@@ -177,8 +186,7 @@ impl<DB: Backend> FromSql<YourSqlType, DB> for YourType {
 
 
 
-## `no_arg_sql_function`
-<a name="2-0-0-no_arg_sql_function"></a>
+## `no_arg_sql_function`<a name="2-0-0-no_arg_sql_function"></a>
 
 The `no_arg_sql_function` was deprecated without direct replacement. At the same time the
 `sql_function!` macro gained support for sql functions without argument. This support generates slightly 
@@ -198,8 +206,7 @@ affects all of the usages of the `no_arg_sql_function!` in third party crates.
 + diesel::select(now())
 ```
 
-### Replacement of `NonAggregate` with `ValidGrouping`
-<a name="2-0-0-upgrade-non-aggregate"></a>
+### Replacement of `NonAggregate` with `ValidGrouping`<a name="2-0-0-upgrade-non-aggregate"></a>
 
 Diesel now fully enforces the aggregation rules, which required us to change the way we represent the aggregation 
 at the type system level. This is used to provide `group_by` support. Diesel's aggregation rules 
@@ -230,8 +237,7 @@ change shows the strictly equivalent version:
 ```
 
 
-## Other changes to generics
-<a name="2-0-0-generic-changes">
+## Other changes to generics<a name="2-0-0-generic-changes">
 
 In addition to the changes listed above, we changed numerous internal details of Diesel. This will have impact on
 most codebases that include non-trivial generic code abstracting over Diesel. This section tries to list as much of those
diff --git a/rust-toolchain b/rust-toolchain
index b7921ae87bcb..3ebf789f5a8d 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,1 +1,1 @@
-1.54.0
+1.56.0


Test patch:
diff --git a/diesel_cli/tests/database_reset.rs b/diesel_cli/tests/database_reset.rs
index 83e4436324cb..23a5a8aa697d 100644
--- a/diesel_cli/tests/database_reset.rs
+++ b/diesel_cli/tests/database_reset.rs
@@ -31,7 +31,7 @@ fn reset_runs_database_setup() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(db.table_exists("posts"));
@@ -101,7 +101,7 @@ fn reset_works_with_migration_dir_by_arg() {
         "foo",
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(db.table_exists("posts"));
@@ -132,7 +132,7 @@ fn reset_works_with_migration_dir_by_env() {
         "bar",
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(db.table_exists("posts"));
@@ -214,7 +214,7 @@ fn reset_respects_migrations_dir_from_diesel_toml() {
         "custom_migrations",
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(db.table_exists("users"));
diff --git a/diesel_cli/tests/database_setup.rs b/diesel_cli/tests/database_setup.rs
index eefee8d47e1f..dfa6b4347fd7 100644
--- a/diesel_cli/tests/database_setup.rs
+++ b/diesel_cli/tests/database_setup.rs
@@ -49,7 +49,7 @@ fn database_setup_runs_migrations_if_no_schema_table() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     // sanity check
@@ -96,7 +96,7 @@ fn database_setup_respects_migration_dir_by_arg_to_database() {
         "foo",
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     // sanity check
@@ -128,7 +128,7 @@ fn database_setup_respects_migration_dir_by_arg() {
         "foo",
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     // sanity check
@@ -160,7 +160,7 @@ fn database_setup_respects_migration_dir_by_env() {
         "bar",
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     // sanity check
@@ -199,7 +199,7 @@ fn database_setup_respects_migrations_dir_from_diesel_toml() {
         "custom_migrations",
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     // sanity check
diff --git a/diesel_cli/tests/migration_generate.rs b/diesel_cli/tests/migration_generate.rs
index a40fe25a60ae..72b10fbbe692 100644
--- a/diesel_cli/tests/migration_generate.rs
+++ b/diesel_cli/tests/migration_generate.rs
@@ -69,6 +69,24 @@ fn migration_generate_creates_a_migration_with_initial_contents() {
     }
 }
 
+#[test]
+fn migration_generate_with_no_down_file_has_no_down_file() {
+    let p = project("migration_name").folder("migrations").build();
+    let result = p
+        .command("migration")
+        .arg("generate")
+        .arg("--no-down")
+        .arg("hello")
+        .run();
+    assert!(result.is_success(), "Command failed: {:?}", result);
+
+    let migrations = p.migrations();
+    let migration = &migrations[0];
+
+    assert!(migration.path().join("up.sql").exists());
+    assert!(!migration.path().join("down.sql").exists());
+}
+
 #[test]
 fn migration_generate_doesnt_require_database_url_to_be_set() {
     let p = project("migration_name").folder("migrations").build();
diff --git a/diesel_cli/tests/migration_list.rs b/diesel_cli/tests/migration_list.rs
index bc4c94e23f65..e94c0aa46ee3 100644
--- a/diesel_cli/tests/migration_list.rs
+++ b/diesel_cli/tests/migration_list.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::expect_fun_call)]
 use chrono::Utc;
 use std::thread::sleep;
 use std::time::Duration;
@@ -17,7 +18,7 @@ fn migration_list_lists_pending_applied_migrations() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(!db.table_exists("users"));
@@ -66,7 +67,7 @@ fn migration_list_lists_migrations_ordered_by_timestamp() {
     p.command("setup").run();
 
     let tag1 = format!("{}_initial", Utc::now().format(TIMESTAMP_FORMAT));
-    p.create_migration(&tag1, "", "");
+    p.create_migration(&tag1, "", Some(""));
 
     let result = p.command("migration").arg("list").run();
     assert!(result.is_success(), "Result was unsuccessful {:?}", result);
@@ -75,7 +76,7 @@ fn migration_list_lists_migrations_ordered_by_timestamp() {
     sleep(Duration::from_millis(1100));
 
     let tag2 = format!("{}_alter", Utc::now().format(TIMESTAMP_FORMAT));
-    p.create_migration(&tag2, "", "");
+    p.create_migration(&tag2, "", Some(""));
 
     let result = p.command("migration").arg("list").run();
     assert!(result.is_success(), "Result was unsuccessful {:?}", result);
@@ -92,28 +93,28 @@ fn migration_list_orders_unknown_timestamps_last() {
     p.command("setup").run();
 
     let tag1 = format!("{}_migration1", Utc::now().format(TIMESTAMP_FORMAT));
-    p.create_migration(&tag1, "", "");
+    p.create_migration(&tag1, "", Some(""));
 
     let tag4 = "abc_migration4";
-    p.create_migration(&tag4, "", "");
+    p.create_migration(tag4, "", Some(""));
 
     let tag5 = "zzz_migration5";
-    p.create_migration(&tag5, "", "");
+    p.create_migration(tag5, "", Some(""));
 
     sleep(Duration::from_millis(1100));
 
     let tag2 = format!("{}_migration2", Utc::now().format(TIMESTAMP_FORMAT));
-    p.create_migration(&tag2, "", "");
+    p.create_migration(&tag2, "", Some(""));
 
     sleep(Duration::from_millis(1100));
 
     let tag3 = format!("{}_migration3", Utc::now().format(TIMESTAMP_FORMAT));
-    p.create_migration(&tag3, "", "");
+    p.create_migration(&tag3, "", Some(""));
 
     let result = p.command("migration").arg("list").run();
     assert!(result.is_success(), "Result was unsuccessful {:?}", result);
     let output = result.stdout();
-    assert_tags_in_order(output, &[&tag1, &tag2, &tag3, &tag4, &tag5]);
+    assert_tags_in_order(output, &[&tag1, &tag2, &tag3, tag4, tag5]);
 }
 
 #[test]
@@ -125,27 +126,27 @@ fn migration_list_orders_nontimestamp_versions_alphabetically() {
     p.command("setup").run();
 
     let tag4 = "a_migration";
-    p.create_migration(&tag4, "", "");
+    p.create_migration(tag4, "", Some(""));
 
     let tag6 = "bc_migration";
-    p.create_migration(&tag6, "", "");
+    p.create_migration(tag6, "", Some(""));
 
     let tag5 = "aa_migration";
-    p.create_migration(&tag5, "", "");
+    p.create_migration(tag5, "", Some(""));
 
     let tag1 = "!wow_migration";
-    p.create_migration(&tag1, "", "");
+    p.create_migration(tag1, "", Some(""));
 
     let tag3 = "7letters";
-    p.create_migration(&tag3, "", "");
+    p.create_migration(tag3, "", Some(""));
 
     let tag2 = format!("{}_stamped_migration", Utc::now().format(TIMESTAMP_FORMAT));
-    p.create_migration(&tag2, "", "");
+    p.create_migration(&tag2, "", Some(""));
 
     let result = p.command("migration").arg("list").run();
     assert!(result.is_success(), "Result was unsuccessful {:?}", result);
     let output = result.stdout();
-    assert_tags_in_order(output, &[&tag1, &tag2, &tag3, &tag4, &tag5, &tag6]);
+    assert_tags_in_order(output, &[tag1, &tag2, tag3, tag4, tag5, tag6]);
 }
 
 #[test]
@@ -157,15 +158,15 @@ fn migration_list_orders_old_and_new_timestamp_forms_mixed_correctly() {
     p.command("setup").run();
 
     let tag1 = "20170505070309_migration";
-    p.create_migration(&tag1, "", "");
+    p.create_migration(tag1, "", Some(""));
 
     let tag2 = "2017-11-23-064836_migration";
-    p.create_migration(&tag2, "", "");
+    p.create_migration(tag2, "", Some(""));
 
     let result = p.command("migration").arg("list").run();
     assert!(result.is_success(), "Result was unsuccessful {:?}", result);
     let output = result.stdout();
-    assert_tags_in_order(output, &[&tag1, &tag2]);
+    assert_tags_in_order(output, &[tag1, tag2]);
 }
 
 #[test]
@@ -188,7 +189,7 @@ fn migration_list_respects_migrations_dir_from_diesel_toml() {
         "custom_migrations",
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(!db.table_exists("users"));
diff --git a/diesel_cli/tests/migration_redo.rs b/diesel_cli/tests/migration_redo.rs
index 1e2b54c36ddf..4c1c00aea97b 100644
--- a/diesel_cli/tests/migration_redo.rs
+++ b/diesel_cli/tests/migration_redo.rs
@@ -6,7 +6,7 @@ fn migration_redo_runs_the_last_migration_down_and_up() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY);",
-        "DROP TABLE users;",
+        Some("DROP TABLE users;"),
     );
 
     // Make sure the project is setup
@@ -37,19 +37,19 @@ fn migration_redo_runs_the_last_two_migrations_down_and_up() {
     p.create_migration(
         "2017-08-31-210424_create_customers",
         "CREATE TABLE customers ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE customers",
+        Some("DROP TABLE customers"),
     );
 
     p.create_migration(
         "2017-09-03-210424_create_contracts",
         "CREATE TABLE contracts ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE contracts",
+        Some("DROP TABLE contracts"),
     );
 
     p.create_migration(
         "2017-09-12-210424_create_bills",
         "CREATE TABLE bills ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE bills",
+        Some("DROP TABLE bills"),
     );
 
     // Make sure the project is setup
@@ -69,8 +69,8 @@ fn migration_redo_runs_the_last_two_migrations_down_and_up() {
         result.stdout()
             == "Rolling back migration 2017-09-12-210424_create_bills\n\
                 Rolling back migration 2017-09-03-210424_create_contracts\n\
-                Running migration 2017-09-12-210424_create_bills\n\
-                Running migration 2017-09-03-210424_create_contracts\n",
+                Running migration 2017-09-03-210424_create_contracts\n\
+                Running migration 2017-09-12-210424_create_bills\n",
         "Unexpected stdout : {}",
         result.stdout()
     );
@@ -88,7 +88,7 @@ fn migration_redo_respects_migration_dir_var() {
         "foo",
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY);",
-        "DROP TABLE users;",
+        Some("DROP TABLE users;"),
     );
 
     // Make sure the project is setup
@@ -121,7 +121,7 @@ fn migration_redo_respects_migration_dir_env() {
         "bar",
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY);",
-        "DROP TABLE users;",
+        Some("DROP TABLE users;"),
     );
 
     // Make sure the project is setup
@@ -154,7 +154,7 @@ fn error_migrations_fails() {
     p.create_migration(
         "redo_error_migrations_fails",
         "CREATE TABLE users (id INTEGER PRIMARY KEY);",
-        "DROP TABLE users};",
+        Some("DROP TABLE users};"),
     );
 
     // Make sure the project is setup
@@ -185,7 +185,7 @@ fn migration_redo_respects_migrations_dir_from_diesel_toml() {
         "custom_migrations",
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY);",
-        "DROP TABLE users;",
+        Some("DROP TABLE users;"),
     );
 
     // Make sure the project is setup
@@ -216,19 +216,19 @@ fn migration_redo_all_runs_all_migrations_down_and_up() {
     p.create_migration(
         "2017-08-31-210424_create_customers",
         "CREATE TABLE customers ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE customers",
+        Some("DROP TABLE customers"),
     );
 
     p.create_migration(
         "2017-09-03-210424_create_contracts",
         "CREATE TABLE contracts ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE contracts",
+        Some("DROP TABLE contracts"),
     );
 
     p.create_migration(
         "2017-09-12-210424_create_bills",
         "CREATE TABLE bills ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE bills",
+        Some("DROP TABLE bills"),
     );
 
     // Make sure the project is setup
@@ -247,9 +247,9 @@ fn migration_redo_all_runs_all_migrations_down_and_up() {
             == "Rolling back migration 2017-09-12-210424_create_bills\n\
                 Rolling back migration 2017-09-03-210424_create_contracts\n\
                 Rolling back migration 2017-08-31-210424_create_customers\n\
-                Running migration 2017-09-12-210424_create_bills\n\
+                Running migration 2017-08-31-210424_create_customers\n\
                 Running migration 2017-09-03-210424_create_contracts\n\
-                Running migration 2017-08-31-210424_create_customers\n",
+                Running migration 2017-09-12-210424_create_bills\n",
         "Unexpected stdout : {}",
         result.stdout()
     );
@@ -269,19 +269,19 @@ fn migration_redo_with_more_than_max_should_redo_all() {
     p.create_migration(
         "2017-08-31-210424_create_customers",
         "CREATE TABLE customers ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE customers",
+        Some("DROP TABLE customers"),
     );
 
     p.create_migration(
         "2017-09-03-210424_create_contracts",
         "CREATE TABLE contracts ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE contracts",
+        Some("DROP TABLE contracts"),
     );
 
     p.create_migration(
         "2017-09-12-210424_create_bills",
         "CREATE TABLE bills ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE bills",
+        Some("DROP TABLE bills"),
     );
 
     // Make sure the project is setup
@@ -305,9 +305,9 @@ fn migration_redo_with_more_than_max_should_redo_all() {
             == "Rolling back migration 2017-09-12-210424_create_bills\n\
                 Rolling back migration 2017-09-03-210424_create_contracts\n\
                 Rolling back migration 2017-08-31-210424_create_customers\n\
-                Running migration 2017-09-12-210424_create_bills\n\
+                Running migration 2017-08-31-210424_create_customers\n\
                 Running migration 2017-09-03-210424_create_contracts\n\
-                Running migration 2017-08-31-210424_create_customers\n",
+                Running migration 2017-09-12-210424_create_bills\n",
         "Unexpected stdout : {}",
         result.stdout()
     );
@@ -339,8 +339,9 @@ fn migration_redo_n_with_a_string_should_throw_an_error() {
     assert!(
         result.stderr()
             == "error: Invalid value \"infinite\" for '--number <REDO_NUMBER>': \
-                infinite isn't a positive integer.\n\nFor more information try --help\n",
-        "Unexpected stderr : {}",
+                invalid digit found in string\n\n\
+                For more information try --help\n",
+        "Unexpected stderr : '{}'",
         result.stderr()
     );
 }
@@ -355,7 +356,7 @@ fn migration_redo_with_zero_should_not_revert_any_migration() {
     p.create_migration(
         "2017-08-31-210424_create_customers",
         "CREATE TABLE customers ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE customers",
+        Some("DROP TABLE customers"),
     );
 
     // Make sure the project is setup
@@ -366,6 +367,6 @@ fn migration_redo_with_zero_should_not_revert_any_migration() {
     // Should not revert any migration.
     let result = p.command("migration").arg("redo").arg("-n").arg("0").run();
 
-    assert!(!result.is_success(), "Result was unsuccessful {:?}", result);
+    assert!(result.is_success(), "Result was unsuccessful {:?}", result);
     assert!(result.stdout() == "");
 }
diff --git a/diesel_cli/tests/migration_revert.rs b/diesel_cli/tests/migration_revert.rs
index e49bbb54e4cc..9fe846fded80 100644
--- a/diesel_cli/tests/migration_revert.rs
+++ b/diesel_cli/tests/migration_revert.rs
@@ -10,7 +10,7 @@ fn migration_revert_runs_the_last_migration_down() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     // Make sure the project is setup
@@ -38,7 +38,7 @@ fn migration_revert_respects_migration_dir_var() {
         "foo",
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     // Make sure the project is setup.
@@ -70,7 +70,7 @@ fn migration_revert_respects_migration_dir_env() {
         "bar",
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     // Make sure the project is setup.
@@ -112,7 +112,7 @@ fn migration_revert_respects_migration_dir_from_diesel_toml() {
         "custom_migrations",
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     // Make sure the project is setup.
@@ -141,19 +141,19 @@ fn migration_revert_runs_the_last_two_migration_down() {
     p.create_migration(
         "2017-08-31-210424_create_customers",
         "CREATE TABLE customers ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE customers",
+        Some("DROP TABLE customers"),
     );
 
     p.create_migration(
         "2017-09-03-210424_create_contracts",
         "CREATE TABLE contracts ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE contracts",
+        Some("DROP TABLE contracts"),
     );
 
     p.create_migration(
         "2017-09-12-210424_create_bills",
         "CREATE TABLE bills ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE bills",
+        Some("DROP TABLE bills"),
     );
 
     // Make sure the project is setup
@@ -194,19 +194,19 @@ fn migration_revert_all_runs_the_migrations_down() {
     p.create_migration(
         "2017-08-31-210424_create_customers",
         "CREATE TABLE customers ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE customers",
+        Some("DROP TABLE customers"),
     );
 
     p.create_migration(
         "2017-09-03-210424_create_contracts",
         "CREATE TABLE contracts ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE contracts",
+        Some("DROP TABLE contracts"),
     );
 
     p.create_migration(
         "2017-09-12-210424_create_bills",
         "CREATE TABLE bills ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE bills",
+        Some("DROP TABLE bills"),
     );
 
     // Make sure the project is setup
@@ -244,7 +244,7 @@ fn migration_revert_with_zero_should_not_revert_any_migration() {
     p.create_migration(
         "2017-08-31-210424_create_customers",
         "CREATE TABLE customers ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE customers",
+        Some("DROP TABLE customers"),
     );
 
     // Make sure the project is setup
@@ -259,8 +259,11 @@ fn migration_revert_with_zero_should_not_revert_any_migration() {
         .arg("-n")
         .arg("0")
         .run();
-
-    assert!(!result.is_success(), "Result was unsuccessful {:?}", result);
+    assert!(
+        result.is_success(),
+        "Result was unsuccessful '{:?}'",
+        result
+    );
     assert!(result.stdout() == "");
 }
 
@@ -281,12 +284,13 @@ fn migration_revert_n_with_a_string_should_throw_an_error() {
         .arg("infinite")
         .run();
 
-    assert!(!result.is_success(), "Result was unsuccessful {:?}", result);
+    assert!(!result.is_success(), "Result was successful {:?}", result);
 
     assert!(
         result.stderr()
             == "error: Invalid value \"infinite\" for '--number <REVERT_NUMBER>': \
-                infinite isn't a positive integer.\n\nFor more information try --help\n",
+                invalid digit found in string\n\n\
+                For more information try --help\n",
         "Unexpected stderr : {}",
         result.stderr()
     );
@@ -302,19 +306,19 @@ fn migration_revert_with_more_than_max_should_revert_all() {
     p.create_migration(
         "2017-08-31-210424_create_customers",
         "CREATE TABLE customers ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE customers",
+        Some("DROP TABLE customers"),
     );
 
     p.create_migration(
         "2017-09-03-210424_create_contracts",
         "CREATE TABLE contracts ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE contracts",
+        Some("DROP TABLE contracts"),
     );
 
     p.create_migration(
         "2017-09-12-210424_create_bills",
         "CREATE TABLE bills ( id INTEGER PRIMARY KEY )",
-        "DROP TABLE bills",
+        Some("DROP TABLE bills"),
     );
 
     // Make sure the project is setup
@@ -346,3 +350,43 @@ fn migration_revert_with_more_than_max_should_revert_all() {
     assert!(!db.table_exists("contracts"));
     assert!(!db.table_exists("bills"));
 }
+
+#[test]
+fn migration_revert_gives_reasonable_error_message_on_missing_down() {
+    let p = project("migration_revert_error_message_on_missing_down")
+        .folder("migrations")
+        .build();
+    let db = database(&p.database_url());
+
+    p.create_migration(
+        "12345_create_users_table",
+        "CREATE TABLE users ( id INTEGER )",
+        None,
+    );
+
+    // Make sure the project is setup
+    p.command("setup").run();
+
+    assert!(db.table_exists("users"));
+
+    let result = p.command("migration").arg("revert").run();
+
+    assert!(
+        !result.is_success(),
+        "Result was successful when it shouldn't be {:?}",
+        result
+    );
+    assert!(
+        result.stdout().contains("Rolling back migration 12345"),
+        "Unexpected stdout {}",
+        result.stdout()
+    );
+    assert!(
+        result
+            .stderr()
+            .contains("Missing `down.sql` file to revert migration"),
+        "Unexpected stderr {}",
+        result.stderr()
+    );
+    assert!(db.table_exists("users"));
+}
diff --git a/diesel_cli/tests/migration_run.rs b/diesel_cli/tests/migration_run.rs
index 0a81831c2c71..a2f9dfebe8fb 100644
--- a/diesel_cli/tests/migration_run.rs
+++ b/diesel_cli/tests/migration_run.rs
@@ -15,7 +15,7 @@ fn migration_run_runs_pending_migrations() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(!db.table_exists("users"));
@@ -44,7 +44,7 @@ fn migration_run_inserts_run_on_timestamps() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     let migrations_done: bool = select(sql::<Bool>(
@@ -104,7 +104,7 @@ fn empty_migrations_are_not_valid() {
 
     p.command("setup").run();
 
-    p.create_migration("12345_empty_migration", "", "");
+    p.create_migration("12345_empty_migration", "", None);
 
     let result = p.command("migration").arg("run").run();
 
@@ -125,7 +125,7 @@ fn error_migrations_fails() {
     p.create_migration(
         "run_error_migrations_fails",
         "CREATE TABLE users (id INTEGER PRIMARY KEY}",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     let result = p.command("migration").arg("run").run();
@@ -149,7 +149,7 @@ fn error_migrations_when_use_invalid_database_url() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     let result = p
@@ -176,7 +176,7 @@ fn any_pending_migrations_works() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     let result = p.command("migration").arg("pending").run();
@@ -195,7 +195,7 @@ fn any_pending_migrations_after_running() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     p.command("migration").arg("run").run();
@@ -216,7 +216,7 @@ fn any_pending_migrations_after_running_and_creating() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     p.command("migration").arg("run").run();
@@ -224,7 +224,7 @@ fn any_pending_migrations_after_running_and_creating() {
     p.create_migration(
         "123456_create_posts_table",
         "CREATE TABLE posts (id INTEGER PRIMARY KEY)",
-        "DROP TABLE posts",
+        Some("DROP TABLE posts"),
     );
 
     let result = p.command("migration").arg("pending").run();
@@ -246,7 +246,7 @@ fn migration_run_runs_pending_migrations_custom_database_url_1() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(!db.table_exists("users"));
@@ -281,7 +281,7 @@ fn migration_run_runs_pending_migrations_custom_database_url_2() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(!db.table_exists("users"));
@@ -317,7 +317,7 @@ fn migration_run_runs_pending_migrations_custom_migration_dir_1() {
         "custom_migrations",
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(!db.table_exists("users"));
@@ -353,7 +353,7 @@ fn migration_run_runs_pending_migrations_custom_migration_dir_2() {
         "custom_migrations",
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(!db.table_exists("users"));
@@ -393,7 +393,7 @@ fn migration_run_updates_schema_if_config_present() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(!p.has_file("src/my_schema.rs"));
@@ -421,7 +421,7 @@ fn migrations_can_be_run_with_no_config_file() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(!db.table_exists("users"));
@@ -452,7 +452,38 @@ fn migrations_can_be_run_with_no_cargo_toml() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
+    );
+
+    assert!(!db.table_exists("users"));
+
+    let result = p.command("migration").arg("run").run();
+
+    assert!(result.is_success(), "Result was unsuccessful {:?}", result);
+    assert!(
+        result.stdout().contains("Running migration 12345"),
+        "Unexpected stdout {}",
+        result.stdout()
+    );
+    assert!(db.table_exists("users"));
+}
+
+#[test]
+fn migrations_can_be_run_with_no_down() {
+    let p = project("migrations_can_be_run_with_no_down")
+        .folder("migrations")
+        .build();
+    let db = database(&p.database_url());
+
+    let cargo_toml_path = Path::new("Cargo.toml");
+    p.delete_single_file(&cargo_toml_path);
+
+    p.command("database").arg("setup").run();
+
+    p.create_migration(
+        "12345_create_users_table",
+        "CREATE TABLE users (id INTEGER PRIMARY KEY)",
+        None,
     );
 
     assert!(!db.table_exists("users"));
@@ -487,7 +518,7 @@ fn verify_schema_errors_if_schema_file_would_change() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(!p.has_file("src/my_schema.rs"));
@@ -500,7 +531,7 @@ fn verify_schema_errors_if_schema_file_would_change() {
     p.create_migration(
         "12346_create_posts_table",
         "CREATE TABLE posts (id INTEGER PRIMARY KEY)",
-        "DROP TABLE posts",
+        Some("DROP TABLE posts"),
     );
 
     let result = p
@@ -548,7 +579,7 @@ fn migration_run_runs_pending_migrations_custom_migrations_dir_from_diesel_toml(
         "custom_migrations",
         "12345_create_users_table",
         "CREATE TABLE users (id INTEGER PRIMARY KEY)",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     assert!(!db.table_exists("users"));
diff --git a/diesel_cli/tests/print_schema.rs b/diesel_cli/tests/print_schema.rs
index fdaa90f9b72b..0e26ef47574f 100644
--- a/diesel_cli/tests/print_schema.rs
+++ b/diesel_cli/tests/print_schema.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::expect_fun_call)]
 use std::fs::File;
 use std::io::prelude::*;
 use std::path::{Path, PathBuf};
@@ -123,6 +124,12 @@ fn print_schema_unsigned() {
     test_print_schema("print_schema_unsigned", vec!["--with-docs"]);
 }
 
+#[test]
+#[cfg(feature = "mysql")]
+fn print_schema_datetime_for_mysql() {
+    test_print_schema("print_schema_datetime_for_mysql", vec!["--with-docs"]);
+}
+
 #[test]
 #[cfg(not(windows))]
 fn print_schema_patch_file() {
@@ -216,6 +223,12 @@ fn print_schema_array_type() {
     test_print_schema("print_schema_array_type", vec![])
 }
 
+#[test]
+#[cfg(feature = "sqlite")]
+fn print_schema_sqlite_implicit_foreign_key_reference() {
+    test_print_schema("print_schema_sqlite_implicit_foreign_key_reference", vec![]);
+}
+
 #[cfg(feature = "sqlite")]
 const BACKEND: &str = "sqlite";
 #[cfg(feature = "postgres")]
@@ -270,7 +283,7 @@ fn test_print_schema_config(test_name: &str, test_path: &Path, schema: String, e
     let p = p.build();
 
     p.command("setup").run();
-    p.create_migration("12345_create_schema", &schema, "");
+    p.create_migration("12345_create_schema", &schema, None);
 
     let result = p.command("migration").arg("run").run();
     assert!(result.is_success(), "Result was unsuccessful {:?}", result);
diff --git a/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/diesel.toml b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/diesel.toml
new file mode 100644
index 000000000000..750e5ba85830
--- /dev/null
+++ b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/diesel.toml
@@ -0,0 +1,3 @@
+[print_schema]
+file = "src/schema.rs"
+with_docs = true
diff --git a/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/expected.rs b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/expected.rs
new file mode 100644
index 000000000000..3d8b74e74a4c
--- /dev/null
+++ b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/expected.rs
@@ -0,0 +1,27 @@
+// @generated automatically by Diesel CLI.
+
+diesel::table! {
+    /// Representation of the `users` table.
+    ///
+    /// (Automatically generated by Diesel.)
+    users (id) {
+        /// The `id` column of the `users` table.
+        ///
+        /// Its SQL type is `Integer`.
+        ///
+        /// (Automatically generated by Diesel.)
+        id -> Integer,
+        /// The `datetime` column of the `users` table.
+        ///
+        /// Its SQL type is `Datetime`.
+        ///
+        /// (Automatically generated by Diesel.)
+        datetime -> Datetime,
+        /// The `nullable_datetime` column of the `users` table.
+        ///
+        /// Its SQL type is `Nullable<Datetime>`.
+        ///
+        /// (Automatically generated by Diesel.)
+        nullable_datetime -> Nullable<Datetime>,
+    }
+}
diff --git a/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/schema.sql b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/schema.sql
new file mode 100644
index 000000000000..0b6f2d2e5e38
--- /dev/null
+++ b/diesel_cli/tests/print_schema/print_schema_datetime_for_mysql/mysql/schema.sql
@@ -0,0 +1,5 @@
+CREATE TABLE users (
+    id INTEGER PRIMARY KEY,
+    datetime DATETIME NOT NULL,
+    nullable_datetime DATETIME
+);
diff --git a/diesel_cli/tests/print_schema/print_schema_sqlite_implicit_foreign_key_reference/diesel.toml b/diesel_cli/tests/print_schema/print_schema_sqlite_implicit_foreign_key_reference/diesel.toml
new file mode 100644
index 000000000000..f57985adb185
--- /dev/null
+++ b/diesel_cli/tests/print_schema/print_schema_sqlite_implicit_foreign_key_reference/diesel.toml
@@ -0,0 +1,2 @@
+[print_schema]
+file = "src/schema.rs"
diff --git a/diesel_cli/tests/print_schema/print_schema_sqlite_implicit_foreign_key_reference/sqlite/expected.rs b/diesel_cli/tests/print_schema/print_schema_sqlite_implicit_foreign_key_reference/sqlite/expected.rs
new file mode 100644
index 000000000000..f791e8ac91f7
--- /dev/null
+++ b/diesel_cli/tests/print_schema/print_schema_sqlite_implicit_foreign_key_reference/sqlite/expected.rs
@@ -0,0 +1,24 @@
+// @generated automatically by Diesel CLI.
+
+diesel::table! {
+    accounts (id) {
+        id -> Integer,
+        account -> Text,
+        data_center_id -> Integer,
+        auth_key -> Binary,
+    }
+}
+
+diesel::table! {
+    data_centers (id) {
+        id -> Integer,
+        name -> Text,
+    }
+}
+
+diesel::joinable!(accounts -> data_centers (data_center_id));
+
+diesel::allow_tables_to_appear_in_same_query!(
+    accounts,
+    data_centers,
+);
diff --git a/diesel_cli/tests/print_schema/print_schema_sqlite_implicit_foreign_key_reference/sqlite/schema.sql b/diesel_cli/tests/print_schema/print_schema_sqlite_implicit_foreign_key_reference/sqlite/schema.sql
new file mode 100644
index 000000000000..0680c88cbf80
--- /dev/null
+++ b/diesel_cli/tests/print_schema/print_schema_sqlite_implicit_foreign_key_reference/sqlite/schema.sql
@@ -0,0 +1,13 @@
+CREATE TABLE data_centers (
+   id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+   name TEXT NOT NULL
+);
+
+CREATE TABLE accounts (
+  id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+  account TEXT NOT NULL,
+  data_center_id INTEGER NOT NULL,
+  auth_key BLOB NOT NULL,
+  UNIQUE (account, data_center_id),
+  FOREIGN KEY (data_center_id) REFERENCES data_centers
+);
diff --git a/diesel_cli/tests/setup.rs b/diesel_cli/tests/setup.rs
index 607487b8da7b..2d6ba09943d9 100644
--- a/diesel_cli/tests/setup.rs
+++ b/diesel_cli/tests/setup.rs
@@ -88,7 +88,7 @@ fn setup_runs_migrations_if_no_schema_table() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     // sanity check
@@ -116,7 +116,7 @@ fn setup_doesnt_run_migrations_if_schema_table_exists() {
     p.create_migration(
         "12345_create_users_table",
         "CREATE TABLE users ( id INTEGER )",
-        "DROP TABLE users",
+        Some("DROP TABLE users"),
     );
 
     let result = p.command("setup").run();
diff --git a/diesel_cli/tests/support/command.rs b/diesel_cli/tests/support/command.rs
index 08abac881ecd..e2aac56c5ba4 100644
--- a/diesel_cli/tests/support/command.rs
+++ b/diesel_cli/tests/support/command.rs
@@ -46,7 +46,7 @@ impl TestCommand {
             .build_command()
             .output()
             .expect("failed to execute process");
-        CommandResult { output: output }
+        CommandResult { output }
     }
 
     fn build_command(&self) -> Command {
diff --git a/diesel_cli/tests/support/mod.rs b/diesel_cli/tests/support/mod.rs
index 6c6e5cd5b674..56f407bf9cce 100644
--- a/diesel_cli/tests/support/mod.rs
+++ b/diesel_cli/tests/support/mod.rs
@@ -4,9 +4,8 @@ macro_rules! try_drop {
         match $e {
             Ok(x) => x,
             Err(e) => {
-                use std::io::{stderr, Write};
                 if ::std::thread::panicking() {
-                    write!(stderr(), "{}: {:?}", $msg, e).unwrap();
+                    eprintln!("{}: {:?}", $msg, e);
                     return;
                 } else {
                     panic!("{}: {:?}", $msg, e);
diff --git a/diesel_cli/tests/support/mysql_database.rs b/diesel_cli/tests/support/mysql_database.rs
index 93ac35423d21..9618876f22c1 100644
--- a/diesel_cli/tests/support/mysql_database.rs
+++ b/diesel_cli/tests/support/mysql_database.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::expect_fun_call)]
 use diesel::connection::SimpleConnection;
 use diesel::dsl::sql;
 use diesel::sql_types::Bool;
@@ -50,7 +51,7 @@ impl Database {
     }
 
     fn split_url(&self) -> (String, String) {
-        let mut split: Vec<&str> = self.url.split("/").collect();
+        let mut split: Vec<&str> = self.url.split('/').collect();
         let database = split.pop().unwrap();
         let mysql_url = format!("{}/{}", split.join("/"), "information_schema");
         (database.into(), mysql_url)
diff --git a/diesel_cli/tests/support/postgres_database.rs b/diesel_cli/tests/support/postgres_database.rs
index e3d1b074dc2b..e2eede17b389 100644
--- a/diesel_cli/tests/support/postgres_database.rs
+++ b/diesel_cli/tests/support/postgres_database.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::expect_fun_call)]
 use diesel::connection::SimpleConnection;
 use diesel::dsl::sql;
 use diesel::sql_types::Bool;
@@ -49,7 +50,7 @@ impl Database {
     }
 
     fn split_url(&self) -> (String, String) {
-        let mut split: Vec<&str> = self.url.split("/").collect();
+        let mut split: Vec<&str> = self.url.split('/').collect();
         let database = split.pop().unwrap();
         let postgres_url = format!("{}/{}", split.join("/"), "postgres");
         (database.into(), postgres_url)
diff --git a/diesel_cli/tests/support/project_builder.rs b/diesel_cli/tests/support/project_builder.rs
index b502d482f5cb..21a6695f6708 100644
--- a/diesel_cli/tests/support/project_builder.rs
+++ b/diesel_cli/tests/support/project_builder.rs
@@ -84,7 +84,7 @@ impl Project {
             .read_dir()
             .expect("Error reading directory")
             .map(|e| Migration {
-                path: e.expect("error reading entry").path().into(),
+                path: e.expect("error reading entry").path(),
             })
             .collect()
     }
@@ -156,19 +156,27 @@ impl Project {
         migration_path.display().to_string()
     }
 
-    pub fn create_migration(&self, name: &str, up: &str, down: &str) {
+    pub fn create_migration(&self, name: &str, up: &str, down: Option<&str>) {
         self.create_migration_in_directory("migrations", name, up, down);
     }
 
-    pub fn create_migration_in_directory(&self, directory: &str, name: &str, up: &str, down: &str) {
+    pub fn create_migration_in_directory(
+        &self,
+        directory: &str,
+        name: &str,
+        up: &str,
+        down: Option<&str>,
+    ) {
         let migration_path = self.directory.path().join(directory).join(name);
         fs::create_dir(&migration_path)
             .expect("Migrations folder must exist to create a migration");
         let mut up_file = fs::File::create(&migration_path.join("up.sql")).unwrap();
         up_file.write_all(up.as_bytes()).unwrap();
 
-        let mut down_file = fs::File::create(&migration_path.join("down.sql")).unwrap();
-        down_file.write_all(down.as_bytes()).unwrap();
+        if let Some(down) = down {
+            let mut down_file = fs::File::create(&migration_path.join("down.sql")).unwrap();
+            down_file.write_all(down.as_bytes()).unwrap();
+        }
     }
 }
 
diff --git a/diesel_cli/tests/support/sqlite_database.rs b/diesel_cli/tests/support/sqlite_database.rs
index fe18bf822e94..f039aa8242b5 100644
--- a/diesel_cli/tests/support/sqlite_database.rs
+++ b/diesel_cli/tests/support/sqlite_database.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::expect_fun_call)]
 use diesel::connection::SimpleConnection;
 use diesel::dsl::sql;
 use diesel::sql_types::Bool;
diff --git a/diesel_compile_tests/Cargo.lock b/diesel_compile_tests/Cargo.lock
index 010398bff0b8..502c4cfe96a6 100644
--- a/diesel_compile_tests/Cargo.lock
+++ b/diesel_compile_tests/Cargo.lock
@@ -51,7 +51,7 @@ dependencies = [
 
 [[package]]
 name = "diesel"
-version = "2.0.0"
+version = "2.0.0-rc.0"
 dependencies = [
  "bigdecimal",
  "bitflags",
@@ -84,7 +84,7 @@ dependencies = [
 
 [[package]]
 name = "diesel_derives"
-version = "2.0.0"
+version = "2.0.0-rc.0"
 dependencies = [
  "proc-macro-error",
  "proc-macro2",
diff --git a/diesel_compile_tests/Cargo.toml b/diesel_compile_tests/Cargo.toml
index fdda3f37c9be..2faaaf407833 100644
--- a/diesel_compile_tests/Cargo.toml
+++ b/diesel_compile_tests/Cargo.toml
@@ -3,7 +3,7 @@ name = "diesel_compile_tests"
 version = "0.1.0"
 
 [dependencies]
-diesel = { version = "2.0.0-rc.0", default-features = false, features = ["extras", "sqlite", "postgres", "mysql", "with-deprecated"], path = "../diesel" }
+diesel = { version = "2.0.0-rc.1", default-features = false, features = ["extras", "sqlite", "postgres", "mysql", "with-deprecated"], path = "../diesel" }
 trybuild = "1.0.41"
 
 [workspace]
diff --git a/diesel_compile_tests/tests/fail/aggregate_expression_requires_column_from_same_table.stderr b/diesel_compile_tests/tests/fail/aggregate_expression_requires_column_from_same_table.stderr
index 73872513c64d..dfa8bdcd30b3 100644
--- a/diesel_compile_tests/tests/fail/aggregate_expression_requires_column_from_same_table.stderr
+++ b/diesel_compile_tests/tests/fail/aggregate_expression_requires_column_from_same_table.stderr
@@ -19,11 +19,20 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 19 |     let source = users::table.select(sum(posts::id));
    |                               ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::functions::aggregate_folding::sum::sum<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::functions::aggregate_folding::sum::sum<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectDsl<diesel::expression::functions::aggregate_folding::sum::sum<diesel::sql_types::Integer, posts::columns::id>>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:19:31
@@ -32,11 +41,20 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |                               ^^^^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::functions::aggregate_folding::sum::sum<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::functions::aggregate_folding::sum::sum<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectDsl<diesel::expression::functions::aggregate_folding::sum::sum<diesel::sql_types::Integer, posts::columns::id>>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
   --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:20:38
@@ -59,11 +77,20 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 20 |     let source = users::table.select(avg(posts::id));
    |                               ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::functions::aggregate_folding::avg::avg<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::functions::aggregate_folding::avg::avg<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectDsl<diesel::expression::functions::aggregate_folding::avg::avg<diesel::sql_types::Integer, posts::columns::id>>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:20:31
@@ -72,11 +99,20 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |                               ^^^^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::functions::aggregate_folding::avg::avg<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::functions::aggregate_folding::avg::avg<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectDsl<diesel::expression::functions::aggregate_folding::avg::avg<diesel::sql_types::Integer, posts::columns::id>>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
   --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:21:38
@@ -99,11 +135,20 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 21 |     let source = users::table.select(max(posts::id));
    |                               ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::functions::aggregate_ordering::max::max<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::functions::aggregate_ordering::max::max<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectDsl<diesel::expression::functions::aggregate_ordering::max::max<diesel::sql_types::Integer, posts::columns::id>>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:21:31
@@ -112,11 +157,20 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |                               ^^^^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::functions::aggregate_ordering::max::max<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::functions::aggregate_ordering::max::max<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectDsl<diesel::expression::functions::aggregate_ordering::max::max<diesel::sql_types::Integer, posts::columns::id>>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
   --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:22:38
@@ -139,11 +193,20 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 22 |     let source = users::table.select(min(posts::id));
    |                               ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::functions::aggregate_ordering::min::min<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::functions::aggregate_ordering::min::min<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectDsl<diesel::expression::functions::aggregate_ordering::min::min<diesel::sql_types::Integer, posts::columns::id>>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:22:31
@@ -152,8 +215,17 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |                               ^^^^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/aggregate_expression_requires_column_from_same_table.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::functions::aggregate_ordering::min::min<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::functions::aggregate_ordering::min::min<diesel::sql_types::Integer, posts::columns::id>`
    = note: required because of the requirements on the impl of `SelectDsl<diesel::expression::functions::aggregate_ordering::min::min<diesel::sql_types::Integer, posts::columns::id>>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.stderr b/diesel_compile_tests/tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.stderr
index c20de9bd9205..19f3aa1e64fe 100644
--- a/diesel_compile_tests/tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.stderr
+++ b/diesel_compile_tests/tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.stderr
@@ -12,12 +12,21 @@ error[E0271]: type mismatch resolving `<stuff::table as AppearsInFromClause<more
 31 |         .load(&mut conn);
    |          ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<stuff::table>` for `more_stuff::columns::names`
+note: required because of the requirements on the impl of `AppearsOnTable<stuff::table>` for `more_stuff::columns::names`
+  --> tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.rs:13:1
+   |
+13 | / table! {
+14 | |     more_stuff (names) {
+15 | |         names -> Array<VarChar>,
+16 | |     }
+17 | | }
+   | |_^
    = note: 3 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<stuff::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<stuff::columns::name, diesel::pg::expression::array_comparison::Any<more_stuff::columns::names>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<stuff::table>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<stuff::columns::name, diesel::pg::expression::array_comparison::Any<more_stuff::columns::names>>>>`
    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<stuff::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<stuff::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<stuff::columns::name, diesel::pg::expression::array_comparison::Any<more_stuff::columns::names>>>>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, _, _>` for `SelectStatement<FromClause<stuff::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<stuff::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<stuff::columns::name, diesel::pg::expression::array_comparison::Any<more_stuff::columns::names>>>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `stuff::table: TableNotEqual<more_stuff::table>` is not satisfied
   --> tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.rs:31:10
@@ -26,9 +35,18 @@ error[E0277]: the trait bound `stuff::table: TableNotEqual<more_stuff::table>` i
    |          ^^^^ the trait `TableNotEqual<more_stuff::table>` is not implemented for `stuff::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<more_stuff::table>` for `stuff::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<stuff::table>` for `more_stuff::columns::names`
+note: required because of the requirements on the impl of `AppearsOnTable<stuff::table>` for `more_stuff::columns::names`
+  --> tests/fail/any_is_only_selectable_if_inner_expr_is_selectable.rs:13:1
+   |
+13 | / table! {
+14 | |     more_stuff (names) {
+15 | |         names -> Array<VarChar>,
+16 | |     }
+17 | | }
+   | |_^
    = note: 3 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<stuff::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<stuff::columns::name, diesel::pg::expression::array_comparison::Any<more_stuff::columns::names>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<stuff::table>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<stuff::columns::name, diesel::pg::expression::array_comparison::Any<more_stuff::columns::names>>>>`
    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<stuff::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<stuff::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<stuff::columns::name, diesel::pg::expression::array_comparison::Any<more_stuff::columns::names>>>>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, _, _>` for `SelectStatement<FromClause<stuff::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<stuff::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<stuff::columns::name, diesel::pg::expression::array_comparison::Any<more_stuff::columns::names>>>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/array_expressions_must_be_correct_type.stderr b/diesel_compile_tests/tests/fail/array_expressions_must_be_correct_type.stderr
index a236f053739f..07be69b27394 100644
--- a/diesel_compile_tests/tests/fail/array_expressions_must_be_correct_type.stderr
+++ b/diesel_compile_tests/tests/fail/array_expressions_must_be_correct_type.stderr
@@ -4,17 +4,17 @@ error[E0277]: the trait bound `f64: SelectableExpression<NoFromClause>` is not s
 9   |     select(array((1f64, 3f64))).get_result::<Vec<i32>>(&mut connection);
     |     ^^^^^^ the trait `SelectableExpression<NoFromClause>` is not implemented for `f64`
     |
-   ::: $DIESEL/src/query_builder/functions.rs
-    |
-    |     crate::dsl::BareSelect<T>: AsQuery,
-    |                                ------- required by this bound in `diesel::select`
-    |
     = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `(f64, f64)`
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>`
     = note: required because of the requirements on the impl of `diesel::query_builder::select_clause::SelectClauseExpression<NoFromClause>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>`
     = note: required because of the requirements on the impl of `Query` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>>`
     = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>>`
+note: required by a bound in `diesel::select`
+   --> $DIESEL/src/query_builder/functions.rs
+    |
+    |     crate::dsl::BareSelect<T>: AsQuery,
+    |                                ^^^^^^^ required by this bound in `diesel::select`
 
 error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
    --> tests/fail/array_expressions_must_be_correct_type.rs:9:5
@@ -22,16 +22,16 @@ error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
 9   |     select(array((1f64, 3f64))).get_result::<Vec<i32>>(&mut connection);
     |     ^^^^^^ the trait `ValidGrouping<()>` is not implemented for `f64`
     |
-   ::: $DIESEL/src/query_builder/functions.rs
-    |
-    |     crate::dsl::BareSelect<T>: AsQuery,
-    |                                ------- required by this bound in `diesel::select`
-    |
     = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(f64, f64)`
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>`
     = note: required because of the requirements on the impl of `Query` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>>`
     = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>>`
+note: required by a bound in `diesel::select`
+   --> $DIESEL/src/query_builder/functions.rs
+    |
+    |     crate::dsl::BareSelect<T>: AsQuery,
+    |                                ^^^^^^^ required by this bound in `diesel::select`
 
 error[E0277]: the trait bound `f64: SelectableExpression<NoFromClause>` is not satisfied
  --> tests/fail/array_expressions_must_be_correct_type.rs:9:33
@@ -86,10 +86,18 @@ error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied
 9  |     select(array((1f64, 3f64))).get_result::<Vec<i32>>(&mut connection);
    |            ^^^^^ the trait `diesel::Expression` is not implemented for `f64`
    |
-  ::: $DIESEL/src/pg/expression/array.rs
-   |
-   |     T: AsExpressionList<ST>,
-   |        -------------------- required by this bound in `diesel::dsl::array`
-   |
    = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Integer>` for `f64`
    = note: required because of the requirements on the impl of `AsExpressionList<diesel::sql_types::Integer>` for `(f64, f64)`
+note: required by a bound in `diesel::dsl::array`
+  --> $DIESEL/src/pg/expression/array.rs
+   |
+   |     T: AsExpressionList<ST>,
+   |        ^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::dsl::array`
+
+error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied
+ --> tests/fail/array_expressions_must_be_correct_type.rs:9:12
+  |
+9 |     select(array((1f64, 3f64))).get_result::<Vec<i32>>(&mut connection);
+  |            ^^^^^^^^^^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `f64`
+  |
+  = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Integer>` for `f64`
diff --git a/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr b/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr
index 19531cbf9017..bb87fbccf054 100644
--- a/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr
+++ b/diesel_compile_tests/tests/fail/array_expressions_must_be_same_type.stderr
@@ -4,17 +4,17 @@ error[E0277]: the trait bound `f64: SelectableExpression<NoFromClause>` is not s
 11  |     select(array((1, 3f64))).get_result::<Vec<i32>>(&mut connection).unwrap();
     |     ^^^^^^ the trait `SelectableExpression<NoFromClause>` is not implemented for `f64`
     |
-   ::: $DIESEL/src/query_builder/functions.rs
-    |
-    |     crate::dsl::BareSelect<T>: AsQuery,
-    |                                ------- required by this bound in `diesel::select`
-    |
     = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64)`
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>`
     = note: required because of the requirements on the impl of `diesel::query_builder::select_clause::SelectClauseExpression<NoFromClause>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>`
     = note: required because of the requirements on the impl of `Query` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
     = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
+note: required by a bound in `diesel::select`
+   --> $DIESEL/src/query_builder/functions.rs
+    |
+    |     crate::dsl::BareSelect<T>: AsQuery,
+    |                                ^^^^^^^ required by this bound in `diesel::select`
 
 error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
    --> tests/fail/array_expressions_must_be_same_type.rs:11:5
@@ -22,16 +22,16 @@ error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
 11  |     select(array((1, 3f64))).get_result::<Vec<i32>>(&mut connection).unwrap();
     |     ^^^^^^ the trait `ValidGrouping<()>` is not implemented for `f64`
     |
-   ::: $DIESEL/src/query_builder/functions.rs
-    |
-    |     crate::dsl::BareSelect<T>: AsQuery,
-    |                                ------- required by this bound in `diesel::select`
-    |
-    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64)`
-    = note: 1 redundant requirements hidden
+    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(f64,)`
+    = note: 2 redundant requirements hidden
     = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>`
     = note: required because of the requirements on the impl of `Query` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
     = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
+note: required by a bound in `diesel::select`
+   --> $DIESEL/src/query_builder/functions.rs
+    |
+    |     crate::dsl::BareSelect<T>: AsQuery,
+    |                                ^^^^^^^ required by this bound in `diesel::select`
 
 error[E0277]: the trait bound `f64: SelectableExpression<NoFromClause>` is not satisfied
   --> tests/fail/array_expressions_must_be_same_type.rs:11:30
@@ -52,8 +52,8 @@ error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
 11 |     select(array((1, 3f64))).get_result::<Vec<i32>>(&mut connection).unwrap();
    |                              ^^^^^^^^^^ the trait `ValidGrouping<()>` is not implemented for `f64`
    |
-   = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64)`
-   = note: 1 redundant requirements hidden
+   = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(f64,)`
+   = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>`
    = note: required because of the requirements on the impl of `Query` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, _, Vec<i32>>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
@@ -86,13 +86,13 @@ error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied
 11 |     select(array((1, 3f64))).get_result::<Vec<i32>>(&mut connection).unwrap();
    |            ^^^^^ the trait `diesel::Expression` is not implemented for `f64`
    |
-  ::: $DIESEL/src/pg/expression/array.rs
-   |
-   |     T: AsExpressionList<ST>,
-   |        -------------------- required by this bound in `diesel::dsl::array`
-   |
    = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Integer>` for `f64`
    = note: required because of the requirements on the impl of `AsExpressionList<diesel::sql_types::Integer>` for `(i32, f64)`
+note: required by a bound in `diesel::dsl::array`
+  --> $DIESEL/src/pg/expression/array.rs
+   |
+   |     T: AsExpressionList<ST>,
+   |        ^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::dsl::array`
 
 error[E0277]: the trait bound `{integer}: SelectableExpression<NoFromClause>` is not satisfied
    --> tests/fail/array_expressions_must_be_same_type.rs:12:5
@@ -100,23 +100,23 @@ error[E0277]: the trait bound `{integer}: SelectableExpression<NoFromClause>` is
 12  |     select(array((1, 3f64))).get_result::<Vec<f64>>(&mut connection).unwrap();
     |     ^^^^^^ the trait `SelectableExpression<NoFromClause>` is not implemented for `{integer}`
     |
-   ::: $DIESEL/src/query_builder/functions.rs
-    |
-    |     crate::dsl::BareSelect<T>: AsQuery,
-    |                                ------- required by this bound in `diesel::select`
-    |
     = help: the following implementations were found:
               <&'a T as SelectableExpression<QS>>
               <(T0, T1) as SelectableExpression<QS>>
               <(T0, T1, T2) as SelectableExpression<QS>>
               <(T0, T1, T2, T3) as SelectableExpression<QS>>
-            and 155 others
+            and 158 others
     = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>)`
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
     = note: required because of the requirements on the impl of `diesel::query_builder::select_clause::SelectClauseExpression<NoFromClause>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>`
     = note: required because of the requirements on the impl of `Query` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
     = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
+note: required by a bound in `diesel::select`
+   --> $DIESEL/src/query_builder/functions.rs
+    |
+    |     crate::dsl::BareSelect<T>: AsQuery,
+    |                                ^^^^^^^ required by this bound in `diesel::select`
 
 error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
    --> tests/fail/array_expressions_must_be_same_type.rs:12:5
@@ -124,22 +124,22 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
 12  |     select(array((1, 3f64))).get_result::<Vec<f64>>(&mut connection).unwrap();
     |     ^^^^^^ the trait `ValidGrouping<()>` is not implemented for `{integer}`
     |
-   ::: $DIESEL/src/query_builder/functions.rs
-    |
-    |     crate::dsl::BareSelect<T>: AsQuery,
-    |                                ------- required by this bound in `diesel::select`
-    |
     = help: the following implementations were found:
               <&'a T as ValidGrouping<GB>>
               <(T0, T1) as ValidGrouping<__GroupByClause>>
               <(T0, T1, T2) as ValidGrouping<__GroupByClause>>
               <(T0, T1, T2, T3) as ValidGrouping<__GroupByClause>>
-            and 140 others
+            and 143 others
     = note: required because of the requirements on the impl of `ValidGrouping<()>` for `({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>)`
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
     = note: required because of the requirements on the impl of `Query` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
     = note: required because of the requirements on the impl of `AsQuery` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
+note: required by a bound in `diesel::select`
+   --> $DIESEL/src/query_builder/functions.rs
+    |
+    |     crate::dsl::BareSelect<T>: AsQuery,
+    |                                ^^^^^^^ required by this bound in `diesel::select`
 
 error[E0277]: the trait bound `{integer}: SelectableExpression<NoFromClause>` is not satisfied
   --> tests/fail/array_expressions_must_be_same_type.rs:12:30
@@ -152,7 +152,7 @@ error[E0277]: the trait bound `{integer}: SelectableExpression<NoFromClause>` is
              <(T0, T1) as SelectableExpression<QS>>
              <(T0, T1, T2) as SelectableExpression<QS>>
              <(T0, T1, T2, T3) as SelectableExpression<QS>>
-           and 155 others
+           and 158 others
    = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>)`
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
@@ -171,7 +171,7 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
              <(T0, T1) as ValidGrouping<__GroupByClause>>
              <(T0, T1, T2) as ValidGrouping<__GroupByClause>>
              <(T0, T1, T2, T3) as ValidGrouping<__GroupByClause>>
-           and 140 others
+           and 143 others
    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>)`
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
@@ -189,7 +189,7 @@ error[E0277]: the trait bound `{integer}: QueryFragment<Pg>` is not satisfied
              <() as QueryFragment<DB>>
              <(T0, T1) as QueryFragment<__DB>>
              <(T0, T1, T2) as QueryFragment<__DB>>
-           and 269 others
+           and 273 others
    = note: required because of the requirements on the impl of `QueryFragment<Pg>` for `({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>)`
    = note: 3 redundant requirements hidden
    = note: required because of the requirements on the impl of `QueryFragment<Pg>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
@@ -206,7 +206,7 @@ error[E0277]: the trait bound `{integer}: QueryId` is not satisfied
              <() as QueryId>
              <(T0, T1) as QueryId>
              <(T0, T1, T2) as QueryId>
-           and 231 others
+           and 234 others
    = note: required because of the requirements on the impl of `QueryId` for `({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>)`
    = note: 3 redundant requirements hidden
    = note: required because of the requirements on the impl of `QueryId` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
@@ -218,16 +218,38 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied
 12 |     select(array((1, 3f64))).get_result::<Vec<f64>>(&mut connection).unwrap();
    |            ^^^^^ the trait `diesel::Expression` is not implemented for `{integer}`
    |
-  ::: $DIESEL/src/pg/expression/array.rs
+   = help: the following implementations were found:
+             <&'a T as diesel::Expression>
+             <(T0, T1) as diesel::Expression>
+             <(T0, T1, T2) as diesel::Expression>
+             <(T0, T1, T2, T3) as diesel::Expression>
+           and 123 others
+   = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Double>` for `{integer}`
+   = note: required because of the requirements on the impl of `AsExpressionList<diesel::sql_types::Double>` for `({integer}, f64)`
+note: required by a bound in `diesel::dsl::array`
+  --> $DIESEL/src/pg/expression/array.rs
    |
    |     T: AsExpressionList<ST>,
-   |        -------------------- required by this bound in `diesel::dsl::array`
+   |        ^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::dsl::array`
+
+error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied
+  --> tests/fail/array_expressions_must_be_same_type.rs:11:12
+   |
+11 |     select(array((1, 3f64))).get_result::<Vec<i32>>(&mut connection).unwrap();
+   |            ^^^^^^^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `f64`
+   |
+   = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Integer>` for `f64`
+
+error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied
+  --> tests/fail/array_expressions_must_be_same_type.rs:12:12
+   |
+12 |     select(array((1, 3f64))).get_result::<Vec<f64>>(&mut connection).unwrap();
+   |            ^^^^^^^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `{integer}`
    |
    = help: the following implementations were found:
              <&'a T as diesel::Expression>
              <(T0, T1) as diesel::Expression>
              <(T0, T1, T2) as diesel::Expression>
              <(T0, T1, T2, T3) as diesel::Expression>
-           and 120 others
+           and 123 others
    = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Double>` for `{integer}`
-   = note: required because of the requirements on the impl of `AsExpressionList<diesel::sql_types::Double>` for `({integer}, f64)`
diff --git a/diesel_compile_tests/tests/fail/boxed_queries_and_group_by.stderr b/diesel_compile_tests/tests/fail/boxed_queries_and_group_by.stderr
index d578f4302194..a4f9483ecb75 100644
--- a/diesel_compile_tests/tests/fail/boxed_queries_and_group_by.stderr
+++ b/diesel_compile_tests/tests/fail/boxed_queries_and_group_by.stderr
@@ -69,8 +69,8 @@ error[E0271]: type mismatch resolving `<BoxedSelectStatement<'_, (diesel::sql_ty
 84 |         .group_by(users::id)
    |          ^^^^^^^^ expected struct `BoxedSelectStatement`, found struct `SelectStatement`
    |
-   = note: expected type `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause<users::table>, _>`
-            found struct `SelectStatement<FromClause<BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause<users::table>, _>>>`
+   = note: expected struct `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause<users::table>, _>`
+              found struct `SelectStatement<FromClause<BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause<users::table>, _>>>`
    = note: required because of the requirements on the impl of `GroupByDsl<_>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause<users::table>, _>`
 
 error[E0277]: the trait bound `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause<users::table>, _>: Table` is not satisfied
diff --git a/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_filter.stderr b/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_filter.stderr
index 3b0a284fe965..2a3a608fe729 100644
--- a/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_filter.stderr
+++ b/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_filter.stderr
@@ -4,10 +4,20 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 21 |     users::table.into_boxed::<Pg>().filter(posts::title.eq("Hello"));
    |                                     ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+  --> tests/fail/boxed_queries_require_selectable_expression_for_filter.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |         title -> VarChar,
+17 | |     }
+18 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::title, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>>`
    = note: required because of the requirements on the impl of `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::title, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>>>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause<users::table>, Pg>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/boxed_queries_require_selectable_expression_for_filter.rs:21:37
@@ -16,7 +26,17 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |                                     ^^^^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+  --> tests/fail/boxed_queries_require_selectable_expression_for_filter.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |         title -> VarChar,
+17 | |     }
+18 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::title, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>>`
    = note: required because of the requirements on the impl of `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::title, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>>>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause<users::table>, Pg>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr b/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr
index 26186546641b..0a260f68dfb9 100644
--- a/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr
+++ b/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr
@@ -6,7 +6,17 @@ error[E0277]: the trait bound `FromClause<users::table>: AppearsInFromClause<pos
    |
    = help: the following implementations were found:
              <FromClause<QS2> as AppearsInFromClause<QS1>>
-   = note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `posts::columns::title`
+note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `posts::columns::title`
+  --> tests/fail/boxed_queries_require_selectable_expression_for_order.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |         title -> VarChar,
+17 | |     }
+18 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `diesel::expression::operators::Desc<posts::columns::title>`
    = note: required because of the requirements on the impl of `OrderDsl<diesel::expression::operators::Desc<posts::columns::title>>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause<users::table>, Pg>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/cannot_mix_aggregate_and_non_aggregate_selects.stderr b/diesel_compile_tests/tests/fail/cannot_mix_aggregate_and_non_aggregate_selects.stderr
index 1b0f8ad5b7e9..cccc72b55769 100644
--- a/diesel_compile_tests/tests/fail/cannot_mix_aggregate_and_non_aggregate_selects.stderr
+++ b/diesel_compile_tests/tests/fail/cannot_mix_aggregate_and_non_aggregate_selects.stderr
@@ -31,7 +31,12 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggreg
    = help: the following implementations were found:
              <diesel::expression::is_aggregate::No as MixedAggregates<diesel::expression::is_aggregate::Never>>
              <diesel::expression::is_aggregate::No as MixedAggregates<diesel::expression::is_aggregate::No>>
-   = note: required because of the requirements on the impl of `ValidGrouping<()>` for `__Derived<columns::nullable_int_col, diesel::expression::functions::aggregate_ordering::max::max<diesel::sql_types::Nullable<diesel::sql_types::Integer>, columns::nullable_int_col>>`
+note: required because of the requirements on the impl of `ValidGrouping<()>` for `__Derived<columns::nullable_int_col, diesel::expression::functions::aggregate_ordering::max::max<diesel::sql_types::Nullable<diesel::sql_types::Integer>, columns::nullable_int_col>>`
+  --> tests/fail/cannot_mix_aggregate_and_non_aggregate_selects.rs:14:1
+   |
+14 | sql_function!(fn f(x: Nullable<Integer>, y: Nullable<Integer>) -> Nullable<Integer>);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `f::f<columns::nullable_int_col, diesel::expression::functions::aggregate_ordering::max::max<diesel::sql_types::Nullable<diesel::sql_types::Integer>, columns::nullable_int_col>>`
    = note: required because of the requirements on the impl of `SelectDsl<f::f<columns::nullable_int_col, diesel::expression::functions::aggregate_ordering::max::max<diesel::sql_types::Nullable<diesel::sql_types::Integer>, columns::nullable_int_col>>>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `sql_function` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/cannot_update_target_with_methods_other_than_filter_called.stderr b/diesel_compile_tests/tests/fail/cannot_update_target_with_methods_other_than_filter_called.stderr
index 430c6f632f4d..bc887e6805d6 100644
--- a/diesel_compile_tests/tests/fail/cannot_update_target_with_methods_other_than_filter_called.stderr
+++ b/diesel_compile_tests/tests/fail/cannot_update_target_with_methods_other_than_filter_called.stderr
@@ -4,12 +4,12 @@ error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel:
 15 |     let command = update(users.select(id)).set(id.eq(1));
    |                          ^^^^^^^^^^^^^^^^ the trait `Identifiable` is not implemented for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<columns::id>>`
    |
-  ::: $DIESEL/src/query_builder/functions.rs
+   = note: required because of the requirements on the impl of `IntoUpdateTarget` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<columns::id>>`
+note: required by a bound in `diesel::update`
+  --> $DIESEL/src/query_builder/functions.rs
    |
    | pub fn update<T: IntoUpdateTarget>(source: T) -> UpdateStatement<T::Table, T::WhereClause> {
-   |                  ---------------- required by this bound in `diesel::update`
-   |
-   = note: required because of the requirements on the impl of `IntoUpdateTarget` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<columns::id>>`
+   |                  ^^^^^^^^^^^^^^^^ required by this bound in `diesel::update`
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause<columns::id>>: Identifiable` is not satisfied
   --> tests/fail/cannot_update_target_with_methods_other_than_filter_called.rs:16:26
@@ -17,9 +17,25 @@ error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel:
 16 |     let command = update(users.order(id)).set(id.eq(1));
    |                          ^^^^^^^^^^^^^^^ the trait `Identifiable` is not implemented for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause<columns::id>>`
    |
-  ::: $DIESEL/src/query_builder/functions.rs
+   = note: required because of the requirements on the impl of `IntoUpdateTarget` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause<columns::id>>`
+note: required by a bound in `diesel::update`
+  --> $DIESEL/src/query_builder/functions.rs
    |
    | pub fn update<T: IntoUpdateTarget>(source: T) -> UpdateStatement<T::Table, T::WhereClause> {
-   |                  ---------------- required by this bound in `diesel::update`
+   |                  ^^^^^^^^^^^^^^^^ required by this bound in `diesel::update`
+
+error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<columns::id>>: Identifiable` is not satisfied
+  --> tests/fail/cannot_update_target_with_methods_other_than_filter_called.rs:15:19
+   |
+15 |     let command = update(users.select(id)).set(id.eq(1));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Identifiable` is not implemented for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<columns::id>>`
+   |
+   = note: required because of the requirements on the impl of `IntoUpdateTarget` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<columns::id>>`
+
+error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause<columns::id>>: Identifiable` is not satisfied
+  --> tests/fail/cannot_update_target_with_methods_other_than_filter_called.rs:16:19
+   |
+16 |     let command = update(users.order(id)).set(id.eq(1));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Identifiable` is not implemented for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause<columns::id>>`
    |
    = note: required because of the requirements on the impl of `IntoUpdateTarget` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::OrderClause<columns::id>>`
diff --git a/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr b/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr
index ffa9f34f2f80..81511790bd50 100644
--- a/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr
+++ b/diesel_compile_tests/tests/fail/columns_cannot_be_rhs_of_insert.stderr
@@ -4,7 +4,17 @@ error[E0271]: type mismatch resolving `<NoFromClause as AppearsInFromClause<user
 20 |         .execute(&mut conn)
    |          ^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<NoFromClause>` for `columns::hair_color`
+note: required because of the requirements on the impl of `AppearsOnTable<NoFromClause>` for `columns::hair_color`
+  --> tests/fail/columns_cannot_be_rhs_of_insert.rs:6:1
+   |
+6  | / table! {
+7  | |     users {
+8  | |         id -> Integer,
+9  | |         name -> Text,
+10 | |         hair_color -> Text,
+11 | |     }
+12 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<NoFromClause>` for `&columns::hair_color`
    = note: required because of the requirements on the impl of `InsertValues<users::table, _>` for `ColumnInsertValue<columns::name, &columns::hair_color>`
@@ -12,3 +22,4 @@ error[E0271]: type mismatch resolving `<NoFromClause as AppearsInFromClause<user
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `QueryFragment<_>` for `InsertStatement<users::table, diesel::query_builder::insert_statement::ValuesClause<ColumnInsertValue<columns::name, &columns::hair_color>, users::table>>`
    = note: required because of the requirements on the impl of `ExecuteDsl<_, _>` for `InsertStatement<users::table, diesel::query_builder::insert_statement::ValuesClause<ColumnInsertValue<columns::name, &columns::hair_color>, users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/custom_returning_requires_selectable_expression.stderr b/diesel_compile_tests/tests/fail/custom_returning_requires_selectable_expression.stderr
index 9cbdfd91620e..d32790a3d4d5 100644
--- a/diesel_compile_tests/tests/fail/custom_returning_requires_selectable_expression.stderr
+++ b/diesel_compile_tests/tests/fail/custom_returning_requires_selectable_expression.stderr
@@ -33,11 +33,21 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<bad:
 33 |     let stmt = insert_into(users).values(&new_user).returning((name, bad::age));
    |                                                     ^^^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `bad::columns::age`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `bad::columns::age`
+  --> tests/fail/custom_returning_requires_selectable_expression.rs:12:1
+   |
+12 | / table! {
+13 | |     bad {
+14 | |       id -> Integer,
+15 | |       age -> Integer,
+16 | |     }
+17 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(users::columns::name, bad::columns::age)`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(users::columns::name, bad::columns::age)`
    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, diesel::query_builder::insert_statement::ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<users::columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::private::Insert, diesel::query_builder::returning_clause::ReturningClause<(users::columns::name, bad::columns::age)>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<bad::table>` is not satisfied
   --> tests/fail/custom_returning_requires_selectable_expression.rs:33:53
@@ -46,8 +56,18 @@ error[E0277]: the trait bound `users::table: TableNotEqual<bad::table>` is not s
    |                                                     ^^^^^^^^^ the trait `TableNotEqual<bad::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<bad::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `bad::columns::age`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `bad::columns::age`
+  --> tests/fail/custom_returning_requires_selectable_expression.rs:12:1
+   |
+12 | / table! {
+13 | |     bad {
+14 | |       id -> Integer,
+15 | |       age -> Integer,
+16 | |     }
+17 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(users::columns::name, bad::columns::age)`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(users::columns::name, bad::columns::age)`
    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, diesel::query_builder::insert_statement::ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<users::columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::private::Insert, diesel::query_builder::returning_clause::ReturningClause<(users::columns::name, bad::columns::age)>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr b/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr
index 9604ad2cfb46..5eec2fe1e01f 100644
--- a/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr
+++ b/diesel_compile_tests/tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.stderr
@@ -1,25 +1,27 @@
-error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
+error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not satisfied
   --> tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.rs:17:10
    |
 17 |         .get_result(&mut connection);
-   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
    |
    = help: the following implementations were found:
-             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, backend::sql_dialect::returning_clause::PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, sqlite::backend::SqliteReturningClause>>
              <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB>>
    = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `DeleteStatement<users::table, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>>>, diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, diesel::SqliteConnection, _>` for `DeleteStatement<users::table, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>>>>`
 
-error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<columns::name>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
+error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<columns::name>: QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not satisfied
   --> tests/fail/delete_statement_does_not_support_returning_methods_on_sqlite.rs:21:10
    |
 21 |         .get_result(&mut connection);
-   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
    |
    = help: the following implementations were found:
-             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, backend::sql_dialect::returning_clause::PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, sqlite::backend::SqliteReturningClause>>
              <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB>>
    = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
    = note: 1 redundant requirements hidden
diff --git a/diesel_compile_tests/tests/fail/derive/bad_insertable.rs b/diesel_compile_tests/tests/fail/derive/bad_insertable.rs
new file mode 100644
index 000000000000..2e262ecaa493
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/derive/bad_insertable.rs
@@ -0,0 +1,16 @@
+use diesel::prelude::*;
+
+table! {
+    users(id) {
+        id -> Integer,
+        name -> Text,
+    }
+}
+
+#[derive(Insertable)]
+struct User {
+    id: String,
+    name: i32,
+}
+
+fn main() {}
diff --git a/diesel_compile_tests/tests/fail/derive/bad_insertable.stderr b/diesel_compile_tests/tests/fail/derive/bad_insertable.stderr
new file mode 100644
index 000000000000..ce08feaf7e4a
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/derive/bad_insertable.stderr
@@ -0,0 +1,33 @@
+error[E0277]: the trait bound `std::string::String: diesel::Expression` is not satisfied
+  --> tests/fail/derive/bad_insertable.rs:12:5
+   |
+12 |     id: String,
+   |     ^^ the trait `diesel::Expression` is not implemented for `std::string::String`
+   |
+   = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Integer>` for `std::string::String`
+
+error[E0277]: the trait bound `i32: diesel::Expression` is not satisfied
+  --> tests/fail/derive/bad_insertable.rs:13:5
+   |
+13 |     name: i32,
+   |     ^^^^ the trait `diesel::Expression` is not implemented for `i32`
+   |
+   = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `i32`
+
+error[E0277]: the trait bound `std::string::String: diesel::Expression` is not satisfied
+  --> tests/fail/derive/bad_insertable.rs:12:5
+   |
+12 |     id: String,
+   |     ^^ the trait `diesel::Expression` is not implemented for `std::string::String`
+   |
+   = note: required because of the requirements on the impl of `diesel::Expression` for `&'insert std::string::String`
+   = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Integer>` for `&'insert std::string::String`
+
+error[E0277]: the trait bound `i32: diesel::Expression` is not satisfied
+  --> tests/fail/derive/bad_insertable.rs:13:5
+   |
+13 |     name: i32,
+   |     ^^^^ the trait `diesel::Expression` is not implemented for `i32`
+   |
+   = note: required because of the requirements on the impl of `diesel::Expression` for `&'insert i32`
+   = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `&'insert i32`
diff --git a/diesel_compile_tests/tests/fail/distinct_on_allows_only_fields_of_table.stderr b/diesel_compile_tests/tests/fail/distinct_on_allows_only_fields_of_table.stderr
index 6b254b6f7570..68ed441415a1 100644
--- a/diesel_compile_tests/tests/fail/distinct_on_allows_only_fields_of_table.stderr
+++ b/diesel_compile_tests/tests/fail/distinct_on_allows_only_fields_of_table.stderr
@@ -41,11 +41,21 @@ error[E0271]: type mismatch resolving `<posts::table as AppearsInFromClause<user
 25 |     posts::table.distinct_on((posts::name, users::name)).get_result(&mut connection);
    |                  ^^^^^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<posts::table>` for `users::columns::name`
+note: required because of the requirements on the impl of `AppearsOnTable<posts::table>` for `users::columns::name`
+  --> tests/fail/distinct_on_allows_only_fields_of_table.rs:5:1
+   |
+5  | / table! {
+6  | |     users {
+7  | |         id -> Integer,
+8  | |         name -> VarChar,
+9  | |     }
+10 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<posts::table>` for `(posts::columns::name, users::columns::name)`
    = note: required because of the requirements on the impl of `SelectableExpression<posts::table>` for `(posts::columns::name, users::columns::name)`
    = note: required because of the requirements on the impl of `DistinctOnDsl<(posts::columns::name, users::columns::name)>` for `posts::table`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `posts::table: TableNotEqual<users::table>` is not satisfied
   --> tests/fail/distinct_on_allows_only_fields_of_table.rs:25:18
@@ -54,8 +64,18 @@ error[E0277]: the trait bound `posts::table: TableNotEqual<users::table>` is not
    |                  ^^^^^^^^^^^ the trait `TableNotEqual<users::table>` is not implemented for `posts::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<users::table>` for `posts::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<posts::table>` for `users::columns::name`
+note: required because of the requirements on the impl of `AppearsOnTable<posts::table>` for `users::columns::name`
+  --> tests/fail/distinct_on_allows_only_fields_of_table.rs:5:1
+   |
+5  | / table! {
+6  | |     users {
+7  | |         id -> Integer,
+8  | |         name -> VarChar,
+9  | |     }
+10 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<posts::table>` for `(posts::columns::name, users::columns::name)`
    = note: required because of the requirements on the impl of `SelectableExpression<posts::table>` for `(posts::columns::name, users::columns::name)`
    = note: required because of the requirements on the impl of `DistinctOnDsl<(posts::columns::name, users::columns::name)>` for `posts::table`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/distinct_on_requires_matching_order_clause.stderr b/diesel_compile_tests/tests/fail/distinct_on_requires_matching_order_clause.stderr
index 0441b7d7725c..94bcfb7b03b6 100644
--- a/diesel_compile_tests/tests/fail/distinct_on_requires_matching_order_clause.stderr
+++ b/diesel_compile_tests/tests/fail/distinct_on_requires_matching_order_clause.stderr
@@ -27,7 +27,7 @@ error[E0277]: the trait bound `diesel::query_builder::order_clause::OrderClause<
              <diesel::query_builder::order_clause::OrderClause<(__D, T0)> as query_dsl::order_dsl::ValidOrderingForDistinct<DistinctOnClause<__D>>>
              <diesel::query_builder::order_clause::OrderClause<(__D, T0, T1)> as query_dsl::order_dsl::ValidOrderingForDistinct<DistinctOnClause<__D>>>
              <diesel::query_builder::order_clause::OrderClause<(__D, T0, T1, T2)> as query_dsl::order_dsl::ValidOrderingForDistinct<DistinctOnClause<__D>>>
-           and 14 others
+           and 18 others
    = note: required because of the requirements on the impl of `OrderDsl<columns::id>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, DistinctOnClause<columns::name>>`
 
 error[E0308]: mismatched types
@@ -59,5 +59,5 @@ error[E0277]: the trait bound `diesel::query_builder::order_clause::OrderClause<
              <diesel::query_builder::order_clause::OrderClause<(__D, T0)> as query_dsl::order_dsl::ValidOrderingForDistinct<DistinctOnClause<__D>>>
              <diesel::query_builder::order_clause::OrderClause<(__D, T0, T1)> as query_dsl::order_dsl::ValidOrderingForDistinct<DistinctOnClause<__D>>>
              <diesel::query_builder::order_clause::OrderClause<(__D, T0, T1, T2)> as query_dsl::order_dsl::ValidOrderingForDistinct<DistinctOnClause<__D>>>
-           and 14 others
+           and 18 others
    = note: required because of the requirements on the impl of `OrderDsl<columns::id>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, DistinctOnClause<columns::name>>`
diff --git a/diesel_compile_tests/tests/fail/ensure_sqlite_cannot_access_memory_of_droped_bind.rs b/diesel_compile_tests/tests/fail/ensure_sqlite_cannot_access_memory_of_droped_bind.rs
index 21f1105912e5..ecf6f1619d06 100644
--- a/diesel_compile_tests/tests/fail/ensure_sqlite_cannot_access_memory_of_droped_bind.rs
+++ b/diesel_compile_tests/tests/fail/ensure_sqlite_cannot_access_memory_of_droped_bind.rs
@@ -1,4 +1,5 @@
 use diesel::prelude::*;
+use diesel::connection::{LoadConnection, DefaultLoadingMode};
 use diesel::sql_types;
 
 fn main() {
@@ -9,7 +10,7 @@ fn main() {
 
         let query = diesel::select((&buf as &[u8]).into_sql::<sql_types::Binary>());
 
-        let mut iter = Connection::load(&mut connection, query).unwrap();
+        let mut iter = LoadConnection::load(&mut connection, query).unwrap();
 
         // Sqlite borrows the buffer internally, so droping it here is not allowed
         // while the statement is still alive.
@@ -27,7 +28,7 @@ fn main() {
 
         let query = diesel::select((&buf as &[u8]).into_sql::<sql_types::Binary>());
 
-        let mut iter = Connection::load(&mut connection, query).unwrap();
+        let mut iter = LoadConnection::<DefaultLoadingMode>::load(&mut connection, query).unwrap();
 
         std::mem::drop(buf);
 
@@ -42,7 +43,7 @@ fn main() {
 
         let query = diesel::select((&buf as &[u8]).into_sql::<sql_types::Binary>());
 
-        let mut iter = Connection::load(&mut connection, query).unwrap();
+        let mut iter = LoadConnection::load(&mut connection, query).unwrap();
 
         std::mem::drop(buf);
 
@@ -57,7 +58,7 @@ fn main() {
 
         let query = diesel::select((&buf as &[u8]).into_sql::<sql_types::Binary>());
 
-        let mut iter = Connection::load(&mut connection, query).unwrap();
+        let mut iter = LoadConnection::load(&mut connection, query).unwrap();
 
         assert_eq!(iter.next().is_some(), true);
         assert_eq!(iter.next().is_none(), true);
diff --git a/diesel_compile_tests/tests/fail/ensure_sqlite_cannot_access_memory_of_droped_bind.stderr b/diesel_compile_tests/tests/fail/ensure_sqlite_cannot_access_memory_of_droped_bind.stderr
index b4144034b914..077cd8793b3e 100644
--- a/diesel_compile_tests/tests/fail/ensure_sqlite_cannot_access_memory_of_droped_bind.stderr
+++ b/diesel_compile_tests/tests/fail/ensure_sqlite_cannot_access_memory_of_droped_bind.stderr
@@ -1,11 +1,11 @@
 error[E0505]: cannot move out of `buf` because it is borrowed
-  --> $DIR/ensure_sqlite_cannot_access_memory_of_droped_bind.rs:16:24
+  --> tests/fail/ensure_sqlite_cannot_access_memory_of_droped_bind.rs:17:24
    |
-10 |         let query = diesel::select((&buf as &[u8]).into_sql::<sql_types::Binary>());
+11 |         let query = diesel::select((&buf as &[u8]).into_sql::<sql_types::Binary>());
    |                                     ---- borrow of `buf` occurs here
 ...
-16 |         std::mem::drop(buf);
+17 |         std::mem::drop(buf);
    |                        ^^^ move out of `buf` occurs here
-17 |
-18 |         assert_eq!(iter.next().is_some(), true);
+18 |
+19 |         assert_eq!(iter.next().is_some(), true);
    |                    ---- borrow later used here
diff --git a/diesel_compile_tests/tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.stderr b/diesel_compile_tests/tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.stderr
index 3b62e822f9ef..ccd8c98f15b7 100644
--- a/diesel_compile_tests/tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.stderr
+++ b/diesel_compile_tests/tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.stderr
@@ -4,12 +4,22 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 32 |         .load::<User>(&mut conn);
    |          ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |         title -> VarChar,
+17 | |     }
+18 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<users::table>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>`
    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, _, User>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Once`
   --> tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.rs:36:10
@@ -17,10 +27,20 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 36 |         .filter(posts::id.eq(1));
    |          ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |         title -> VarChar,
+17 | |     }
+18 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
    = note: required because of the requirements on the impl of `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause<users::table>, Pg>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>: BoxedDsl<'_, Pg>` is not satisfied
   --> tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.rs:39:10
@@ -38,12 +58,22 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 43 |         .load::<User>(&mut conn);
    |          ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+  --> tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |         title -> VarChar,
+17 | |     }
+18 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, posts::columns::title>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<users::table>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, posts::columns::title>>>`
    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, posts::columns::title>>>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, _, User>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, posts::columns::title>>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Once`
   --> tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.rs:47:10
@@ -51,10 +81,20 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 47 |         .filter(users::name.eq(posts::title));
    |          ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+  --> tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |         title -> VarChar,
+17 | |     }
+18 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, posts::columns::title>>`
    = note: required because of the requirements on the impl of `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, posts::columns::title>>>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), FromClause<users::table>, Pg>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, posts::columns::title>>>>: BoxedDsl<'_, Pg>` is not satisfied
   --> tests/fail/filter_cannot_take_comparison_for_columns_from_another_table.rs:51:10
diff --git a/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr b/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr
index 474029af0af7..2a109d996122 100644
--- a/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr
+++ b/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr
@@ -32,7 +32,7 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied
              <(T0, T1) as diesel::Expression>
              <(T0, T1, T2) as diesel::Expression>
              <(T0, T1, T2, T3) as diesel::Expression>
-           and 124 others
+           and 127 others
    = note: required because of the requirements on the impl of `diesel::Expression` for `diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>`
    = note: required because of the requirements on the impl of `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>>>` for `SelectStatement<FromClause<string_primary_key::table>>`
 
@@ -47,7 +47,7 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
              <(T0, T1) as ValidGrouping<__GroupByClause>>
              <(T0, T1, T2) as ValidGrouping<__GroupByClause>>
              <(T0, T1, T2, T3) as ValidGrouping<__GroupByClause>>
-           and 146 others
+           and 149 others
    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>`
    = note: required because of the requirements on the impl of `NonAggregate` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>>`
    = note: required because of the requirements on the impl of `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>>>` for `SelectStatement<FromClause<string_primary_key::table>>`
diff --git a/diesel_compile_tests/tests/fail/having_cant_be_used_without_group_by.stderr b/diesel_compile_tests/tests/fail/having_cant_be_used_without_group_by.stderr
index 30706d888636..9da50db3f153 100644
--- a/diesel_compile_tests/tests/fail/having_cant_be_used_without_group_by.stderr
+++ b/diesel_compile_tests/tests/fail/having_cant_be_used_without_group_by.stderr
@@ -21,10 +21,21 @@ error[E0271]: type mismatch resolving `<FromClause<users::table> as AppearsInFro
 30 |     users::table.select(users::name).group_by(users::id).having(posts::id.eq(42)).load(&mut conn);
    |                                                          ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `posts::columns::id`
+  --> tests/fail/having_cant_be_used_without_group_by.rs:12:1
+   |
+12 | / table! {
+13 | |     posts {
+14 | |         id -> Integer,
+15 | |         title -> Text,
+16 | |         user_id -> Integer,
+17 | |     }
+18 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
    = note: required because of the requirements on the impl of `HavingDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<users::columns::name>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<users::columns::id>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0271]: type mismatch resolving `<FromClause<users::table> as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Once`
   --> tests/fail/having_cant_be_used_without_group_by.rs:32:71
@@ -32,7 +43,18 @@ error[E0271]: type mismatch resolving `<FromClause<users::table> as AppearsInFro
 32 |     users::table.select(users::name).group_by(users::id).into_boxed().having(posts::id.eq(42)).load(&mut conn);
    |                                                                       ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `posts::columns::id`
+  --> tests/fail/having_cant_be_used_without_group_by.rs:12:1
+   |
+12 | / table! {
+13 | |     posts {
+14 | |         id -> Integer,
+15 | |         title -> Text,
+16 | |         user_id -> Integer,
+17 | |     }
+18 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
    = note: required because of the requirements on the impl of `HavingDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>` for `BoxedSelectStatement<'_, diesel::sql_types::Text, FromClause<users::table>, _, users::columns::id>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/insert_requires_value_of_same_type_as_column.stderr b/diesel_compile_tests/tests/fail/insert_requires_value_of_same_type_as_column.stderr
index e5677bc9515c..cab95e1a46c7 100644
--- a/diesel_compile_tests/tests/fail/insert_requires_value_of_same_type_as_column.stderr
+++ b/diesel_compile_tests/tests/fail/insert_requires_value_of_same_type_as_column.stderr
@@ -9,5 +9,5 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied
              <(T0, T1) as diesel::Expression>
              <(T0, T1, T2) as diesel::Expression>
              <(T0, T1, T2, T3) as diesel::Expression>
-           and 124 others
+           and 127 others
    = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `{integer}`
diff --git a/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr b/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr
index 78e8b8b44416..24b19eff4876 100644
--- a/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr
+++ b/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.stderr
@@ -1,25 +1,27 @@
-error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
+error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not satisfied
   --> tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.rs:29:10
    |
 29 |         .get_result::<User>(&mut connection);
-   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
    |
    = help: the following implementations were found:
-             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, backend::sql_dialect::returning_clause::PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, sqlite::backend::SqliteReturningClause>>
              <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB>>
    = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `InsertStatement<users::table, diesel::query_builder::insert_statement::ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::private::Insert, diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, SqliteConnection, User>` for `InsertStatement<users::table, diesel::query_builder::insert_statement::ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>>`
 
-error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<columns::name>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
+error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<columns::name>: QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not satisfied
   --> tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.rs:34:10
    |
 34 |         .get_result::<String>(&mut connection);
-   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
    |
    = help: the following implementations were found:
-             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, backend::sql_dialect::returning_clause::PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, sqlite::backend::SqliteReturningClause>>
              <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB>>
    = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
    = note: 1 redundant requirements hidden
diff --git a/diesel_compile_tests/tests/fail/join_with_explicit_on_requires_valid_boolean_expression.stderr b/diesel_compile_tests/tests/fail/join_with_explicit_on_requires_valid_boolean_expression.stderr
index cfa527084370..83c8801a7be0 100644
--- a/diesel_compile_tests/tests/fail/join_with_explicit_on_requires_valid_boolean_expression.stderr
+++ b/diesel_compile_tests/tests/fail/join_with_explicit_on_requires_valid_boolean_expression.stderr
@@ -4,11 +4,20 @@ error[E0271]: type mismatch resolving `<diesel::internal::table_macro::Join<user
 31 |     let _ = users::table.inner_join(posts::table.on(users::id.eq(comments::id)));
    |                          ^^^^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<users::table, posts::table, Inner>>` for `comments::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<users::table, posts::table, Inner>>` for `comments::columns::id`
+  --> tests/fail/join_with_explicit_on_requires_valid_boolean_expression.rs:17:1
+   |
+17 | / table! {
+18 | |     comments {
+19 | |         id -> Integer,
+20 | |     }
+21 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<users::table, posts::table, Inner>>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::id, comments::columns::id>>`
    = note: required because of the requirements on the impl of `QuerySource` for `JoinOn<diesel::internal::table_macro::Join<users::table, posts::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::id, comments::columns::id>>>`
    = note: required because of the requirements on the impl of `InternalJoinDsl<posts::table, Inner, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::id, comments::columns::id>>>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `diesel::sql_types::Integer: BoolOrNullableBool` is not satisfied
   --> tests/fail/join_with_explicit_on_requires_valid_boolean_expression.rs:33:26
diff --git a/diesel_compile_tests/tests/fail/order_requires_column_from_same_table.stderr b/diesel_compile_tests/tests/fail/order_requires_column_from_same_table.stderr
index b4ff3311c855..e715e46d573c 100644
--- a/diesel_compile_tests/tests/fail/order_requires_column_from_same_table.stderr
+++ b/diesel_compile_tests/tests/fail/order_requires_column_from_same_table.stderr
@@ -6,5 +6,14 @@ error[E0277]: the trait bound `FromClause<users::table>: AppearsInFromClause<pos
    |
    = help: the following implementations were found:
              <FromClause<QS2> as AppearsInFromClause<QS1>>
-   = note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `posts::columns::id`
+  --> tests/fail/order_requires_column_from_same_table.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: required because of the requirements on the impl of `OrderDsl<posts::columns::id>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/ordering_functions_require_ord.stderr b/diesel_compile_tests/tests/fail/ordering_functions_require_ord.stderr
index 6f2b6743edd4..0a4cf3773654 100644
--- a/diesel_compile_tests/tests/fail/ordering_functions_require_ord.stderr
+++ b/diesel_compile_tests/tests/fail/ordering_functions_require_ord.stderr
@@ -4,12 +4,12 @@ error[E0277]: the trait bound `diesel::sql_types::Bool: SqlOrd` is not satisfied
 13 |     let source = stuff::table.select(max(stuff::b));
    |                                      ^^^ the trait `SqlOrd` is not implemented for `diesel::sql_types::Bool`
    |
-  ::: $DIESEL/src/expression/functions/aggregate_ordering.rs
+   = note: required because of the requirements on the impl of `diesel::expression::functions::aggregate_ordering::private::SqlOrdAggregate` for `diesel::sql_types::Bool`
+note: required by a bound in `diesel::dsl::max`
+  --> $DIESEL/src/expression/functions/aggregate_ordering.rs
    |
    |     fn max<ST: SqlOrdAggregate>(expr: ST) -> ST::Ret;
-   |                --------------- required by this bound in `diesel::dsl::max`
-   |
-   = note: required because of the requirements on the impl of `diesel::expression::functions::aggregate_ordering::private::SqlOrdAggregate` for `diesel::sql_types::Bool`
+   |                ^^^^^^^^^^^^^^^ required by this bound in `diesel::dsl::max`
 
 error[E0277]: the trait bound `diesel::sql_types::Bool: SqlOrd` is not satisfied
   --> tests/fail/ordering_functions_require_ord.rs:13:38
@@ -27,12 +27,12 @@ error[E0277]: the trait bound `diesel::sql_types::Bool: SqlOrd` is not satisfied
 14 |     let source = stuff::table.select(min(stuff::b));
    |                                      ^^^ the trait `SqlOrd` is not implemented for `diesel::sql_types::Bool`
    |
-  ::: $DIESEL/src/expression/functions/aggregate_ordering.rs
+   = note: required because of the requirements on the impl of `diesel::expression::functions::aggregate_ordering::private::SqlOrdAggregate` for `diesel::sql_types::Bool`
+note: required by a bound in `diesel::dsl::min`
+  --> $DIESEL/src/expression/functions/aggregate_ordering.rs
    |
    |     fn min<ST: SqlOrdAggregate>(expr: ST) -> ST::Ret;
-   |                --------------- required by this bound in `diesel::dsl::min`
-   |
-   = note: required because of the requirements on the impl of `diesel::expression::functions::aggregate_ordering::private::SqlOrdAggregate` for `diesel::sql_types::Bool`
+   |                ^^^^^^^^^^^^^^^ required by this bound in `diesel::dsl::min`
 
 error[E0277]: the trait bound `diesel::sql_types::Bool: SqlOrd` is not satisfied
   --> tests/fail/ordering_functions_require_ord.rs:14:38
diff --git a/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.rs b/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.rs
new file mode 100644
index 000000000000..9154c1de34fa
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.rs
@@ -0,0 +1,30 @@
+extern crate diesel;
+
+use diesel::prelude::*;
+
+table! {
+    users {
+        id -> Integer,
+        name -> Binary,
+    }
+}
+
+fn main() {
+    use self::users::dsl::*;
+
+    let mut connection = SqliteConnection::establish("").unwrap();
+
+    users
+        .select(name.concat(b"foo".to_vec()))
+        .filter(name.like(b"bar".to_vec()))
+        .filter(name.not_like(b"baz".to_vec()))
+        .get_result::<Vec<u8>>(&mut connection).unwrap();
+
+    let mut connection = MysqlConnection::establish("").unwrap();
+
+    users
+        .select(name.concat(b"foo".to_vec()))
+        .filter(name.like(b"bar".to_vec()))
+        .filter(name.not_like(b"baz".to_vec()))
+        .get_result::<Vec<u8>>(&mut connection).unwrap();
+}
diff --git a/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.stderr b/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.stderr
new file mode 100644
index 000000000000..329e659f6af0
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/pg_specific_binary_expressions_only_usable_with_pg.stderr
@@ -0,0 +1,15 @@
+error[E0271]: type mismatch resolving `<diesel::SqliteConnection as diesel::Connection>::Backend == Pg`
+  --> tests/fail/pg_specific_binary_expressions_only_usable_with_pg.rs:21:10
+   |
+21 |         .get_result::<Vec<u8>>(&mut connection).unwrap();
+   |          ^^^^^^^^^^ expected struct `Sqlite`, found struct `Pg`
+   |
+   = note: required because of the requirements on the impl of `LoadQuery<'_, diesel::SqliteConnection, Vec<u8>>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<diesel::expression::grouped::Grouped<diesel::pg::expression::operators::ConcatBinary<columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Binary, Vec<u8>>>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::And<diesel::expression::grouped::Grouped<diesel::pg::expression::operators::LikeBinary<columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Binary, Vec<u8>>>>, diesel::expression::grouped::Grouped<diesel::pg::expression::operators::NotLikeBinary<columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Binary, Vec<u8>>>>>>>>`
+
+error[E0271]: type mismatch resolving `<diesel::MysqlConnection as diesel::Connection>::Backend == Pg`
+  --> tests/fail/pg_specific_binary_expressions_only_usable_with_pg.rs:29:10
+   |
+29 |         .get_result::<Vec<u8>>(&mut connection).unwrap();
+   |          ^^^^^^^^^^ expected struct `Mysql`, found struct `Pg`
+   |
+   = note: required because of the requirements on the impl of `LoadQuery<'_, diesel::MysqlConnection, Vec<u8>>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<diesel::expression::grouped::Grouped<diesel::pg::expression::operators::ConcatBinary<columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Binary, Vec<u8>>>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::And<diesel::expression::grouped::Grouped<diesel::pg::expression::operators::LikeBinary<columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Binary, Vec<u8>>>>, diesel::expression::grouped::Grouped<diesel::pg::expression::operators::NotLikeBinary<columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Binary, Vec<u8>>>>>>>>`
diff --git a/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.stderr b/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.stderr
index b8c023164115..dcf5f71cc953 100644
--- a/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.stderr
+++ b/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.stderr
@@ -32,8 +32,18 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 56 |         .set(name.eq(posts::title));
    |          ^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+  --> tests/fail/pg_upsert_do_update_requires_valid_update.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |         title -> VarChar,
+17 | |     }
+18 | | }
+   | |_^
    = note: required because of the requirements on the impl of `AsChangeset` for `diesel::expression::operators::Eq<users::columns::name, posts::columns::title>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/pg_upsert_do_update_requires_valid_update.rs:56:10
@@ -42,8 +52,18 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |          ^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+  --> tests/fail/pg_upsert_do_update_requires_valid_update.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |         title -> VarChar,
+17 | |     }
+18 | | }
+   | |_^
    = note: required because of the requirements on the impl of `AsChangeset` for `diesel::expression::operators::Eq<users::columns::name, posts::columns::title>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0271]: type mismatch resolving `<posts::columns::title as Column>::Table == users::table`
   --> tests/fail/pg_upsert_do_update_requires_valid_update.rs:63:10
diff --git a/diesel_compile_tests/tests/fail/right_side_of_left_join_requires_nullable.stderr b/diesel_compile_tests/tests/fail/right_side_of_left_join_requires_nullable.stderr
index e96419c2255e..ae51ed3ca634 100644
--- a/diesel_compile_tests/tests/fail/right_side_of_left_join_requires_nullable.stderr
+++ b/diesel_compile_tests/tests/fail/right_side_of_left_join_requires_nullable.stderr
@@ -57,15 +57,28 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users
 error[E0271]: type mismatch resolving `<NullableExpression<posts::columns::title> as diesel::Expression>::SqlType == diesel::sql_types::Text`
   --> tests/fail/right_side_of_left_join_requires_nullable.rs:48:25
    |
-32 | sql_function!(fn lower(x: Text) -> Text);
-   | ----------------------------------------- required by this bound in `lower`
-...
 48 |     let _ = join.select(lower(posts::title.nullable()));
    |                         ^^^^^ expected struct `diesel::sql_types::Text`, found struct `Nullable`
    |
    = note: expected struct `diesel::sql_types::Text`
               found struct `Nullable<diesel::sql_types::Text>`
    = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `NullableExpression<posts::columns::title>`
+note: required by a bound in `lower`
+  --> tests/fail/right_side_of_left_join_requires_nullable.rs:32:1
+   |
+32 | sql_function!(fn lower(x: Text) -> Text);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `lower`
+   = note: this error originates in the macro `sql_function` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0271]: type mismatch resolving `<NullableExpression<posts::columns::title> as diesel::Expression>::SqlType == diesel::sql_types::Text`
+  --> tests/fail/right_side_of_left_join_requires_nullable.rs:48:25
+   |
+48 |     let _ = join.select(lower(posts::title.nullable()));
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Nullable`, found struct `diesel::sql_types::Text`
+   |
+   = note: expected struct `Nullable<diesel::sql_types::Text>`
+              found struct `diesel::sql_types::Text`
+   = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `NullableExpression<posts::columns::title>`
 
 error[E0271]: type mismatch resolving `<posts::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Never`
   --> tests/fail/right_side_of_left_join_requires_nullable.rs:57:18
@@ -126,15 +139,28 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users
 error[E0271]: type mismatch resolving `<NullableExpression<posts::columns::title> as diesel::Expression>::SqlType == diesel::sql_types::Text`
   --> tests/fail/right_side_of_left_join_requires_nullable.rs:65:25
    |
-32 | sql_function!(fn lower(x: Text) -> Text);
-   | ----------------------------------------- required by this bound in `lower`
-...
 65 |     let _ = join.select(lower(posts::title.nullable()));
    |                         ^^^^^ expected struct `diesel::sql_types::Text`, found struct `Nullable`
    |
    = note: expected struct `diesel::sql_types::Text`
               found struct `Nullable<diesel::sql_types::Text>`
    = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `NullableExpression<posts::columns::title>`
+note: required by a bound in `lower`
+  --> tests/fail/right_side_of_left_join_requires_nullable.rs:32:1
+   |
+32 | sql_function!(fn lower(x: Text) -> Text);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `lower`
+   = note: this error originates in the macro `sql_function` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0271]: type mismatch resolving `<NullableExpression<posts::columns::title> as diesel::Expression>::SqlType == diesel::sql_types::Text`
+  --> tests/fail/right_side_of_left_join_requires_nullable.rs:65:25
+   |
+65 |     let _ = join.select(lower(posts::title.nullable()));
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Nullable`, found struct `diesel::sql_types::Text`
+   |
+   = note: expected struct `Nullable<diesel::sql_types::Text>`
+              found struct `diesel::sql_types::Text`
+   = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `NullableExpression<posts::columns::title>`
 
 error[E0271]: type mismatch resolving `<posts::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Never`
   --> tests/fail/right_side_of_left_join_requires_nullable.rs:74:18
@@ -195,15 +221,28 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users
 error[E0271]: type mismatch resolving `<NullableExpression<posts::columns::title> as diesel::Expression>::SqlType == diesel::sql_types::Text`
   --> tests/fail/right_side_of_left_join_requires_nullable.rs:82:25
    |
-32 | sql_function!(fn lower(x: Text) -> Text);
-   | ----------------------------------------- required by this bound in `lower`
-...
 82 |     let _ = join.select(lower(posts::title.nullable()));
    |                         ^^^^^ expected struct `diesel::sql_types::Text`, found struct `Nullable`
    |
    = note: expected struct `diesel::sql_types::Text`
               found struct `Nullable<diesel::sql_types::Text>`
    = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `NullableExpression<posts::columns::title>`
+note: required by a bound in `lower`
+  --> tests/fail/right_side_of_left_join_requires_nullable.rs:32:1
+   |
+32 | sql_function!(fn lower(x: Text) -> Text);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `lower`
+   = note: this error originates in the macro `sql_function` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0271]: type mismatch resolving `<NullableExpression<posts::columns::title> as diesel::Expression>::SqlType == diesel::sql_types::Text`
+  --> tests/fail/right_side_of_left_join_requires_nullable.rs:82:25
+   |
+82 |     let _ = join.select(lower(posts::title.nullable()));
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Nullable`, found struct `diesel::sql_types::Text`
+   |
+   = note: expected struct `Nullable<diesel::sql_types::Text>`
+              found struct `diesel::sql_types::Text`
+   = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `NullableExpression<posts::columns::title>`
 
 error[E0271]: type mismatch resolving `<SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, posts::table, LeftOuter>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>> as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Never`
   --> tests/fail/right_side_of_left_join_requires_nullable.rs:89:18
@@ -264,15 +303,28 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression<pets:
 error[E0271]: type mismatch resolving `<NullableExpression<posts::columns::title> as diesel::Expression>::SqlType == diesel::sql_types::Text`
   --> tests/fail/right_side_of_left_join_requires_nullable.rs:97:25
    |
-32 | sql_function!(fn lower(x: Text) -> Text);
-   | ----------------------------------------- required by this bound in `lower`
-...
 97 |     let _ = join.select(lower(posts::title.nullable()));
    |                         ^^^^^ expected struct `diesel::sql_types::Text`, found struct `Nullable`
    |
    = note: expected struct `diesel::sql_types::Text`
               found struct `Nullable<diesel::sql_types::Text>`
    = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `NullableExpression<posts::columns::title>`
+note: required by a bound in `lower`
+  --> tests/fail/right_side_of_left_join_requires_nullable.rs:32:1
+   |
+32 | sql_function!(fn lower(x: Text) -> Text);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `lower`
+   = note: this error originates in the macro `sql_function` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0271]: type mismatch resolving `<NullableExpression<posts::columns::title> as diesel::Expression>::SqlType == diesel::sql_types::Text`
+  --> tests/fail/right_side_of_left_join_requires_nullable.rs:97:25
+   |
+97 |     let _ = join.select(lower(posts::title.nullable()));
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Nullable`, found struct `diesel::sql_types::Text`
+   |
+   = note: expected struct `Nullable<diesel::sql_types::Text>`
+              found struct `diesel::sql_types::Text`
+   = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `NullableExpression<posts::columns::title>`
 
 error[E0271]: type mismatch resolving `<posts::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Never`
    --> tests/fail/right_side_of_left_join_requires_nullable.rs:104:18
@@ -333,12 +385,25 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users
 error[E0271]: type mismatch resolving `<NullableExpression<posts::columns::title> as diesel::Expression>::SqlType == diesel::sql_types::Text`
    --> tests/fail/right_side_of_left_join_requires_nullable.rs:112:25
     |
-32  | sql_function!(fn lower(x: Text) -> Text);
-    | ----------------------------------------- required by this bound in `lower`
-...
 112 |     let _ = join.select(lower(posts::title.nullable()));
     |                         ^^^^^ expected struct `diesel::sql_types::Text`, found struct `Nullable`
     |
     = note: expected struct `diesel::sql_types::Text`
                found struct `Nullable<diesel::sql_types::Text>`
     = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `NullableExpression<posts::columns::title>`
+note: required by a bound in `lower`
+   --> tests/fail/right_side_of_left_join_requires_nullable.rs:32:1
+    |
+32  | sql_function!(fn lower(x: Text) -> Text);
+    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `lower`
+    = note: this error originates in the macro `sql_function` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0271]: type mismatch resolving `<NullableExpression<posts::columns::title> as diesel::Expression>::SqlType == diesel::sql_types::Text`
+   --> tests/fail/right_side_of_left_join_requires_nullable.rs:112:25
+    |
+112 |     let _ = join.select(lower(posts::title.nullable()));
+    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Nullable`, found struct `diesel::sql_types::Text`
+    |
+    = note: expected struct `Nullable<diesel::sql_types::Text>`
+               found struct `diesel::sql_types::Text`
+    = note: required because of the requirements on the impl of `AsExpression<diesel::sql_types::Text>` for `NullableExpression<posts::columns::title>`
diff --git a/diesel_compile_tests/tests/fail/select_for_update_cannot_be_mixed_with_some_clauses.stderr b/diesel_compile_tests/tests/fail/select_for_update_cannot_be_mixed_with_some_clauses.stderr
index 1f329045c7f3..dc57f4f5fcc6 100644
--- a/diesel_compile_tests/tests/fail/select_for_update_cannot_be_mixed_with_some_clauses.stderr
+++ b/diesel_compile_tests/tests/fail/select_for_update_cannot_be_mixed_with_some_clauses.stderr
@@ -4,8 +4,8 @@ error[E0271]: type mismatch resolving `<SelectStatement<FromClause<users::table>
 14 |     users.for_update().distinct();
    |                        ^^^^^^^^ expected struct `users::table`, found struct `SelectStatement`
    |
-   = note: expected type `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
-            found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>>, _>`
+   = note: expected struct `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
+              found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>>, _>`
    = note: required because of the requirements on the impl of `DistinctDsl` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>`
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>: Table` is not satisfied
@@ -31,8 +31,8 @@ error[E0271]: type mismatch resolving `<SelectStatement<FromClause<users::table>
 15 |     users.distinct().for_update();
    |                      ^^^^^^^^^^ expected struct `users::table`, found struct `SelectStatement`
    |
-   = note: expected type `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::DistinctClause>`
-            found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::DistinctClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::DistinctClause>>>, diesel::query_builder::distinct_clause::NoDistinctClause>`
+   = note: expected struct `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::DistinctClause>`
+              found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::DistinctClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::DistinctClause>>>, diesel::query_builder::distinct_clause::NoDistinctClause>`
    = note: required because of the requirements on the impl of `LockingDsl<diesel::query_builder::locking_clause::ForUpdate>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::DistinctClause>`
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::DistinctClause>: Table` is not satisfied
@@ -58,8 +58,8 @@ error[E0271]: type mismatch resolving `<SelectStatement<FromClause<users::table>
 16 |     users.for_update().distinct_on(id);
    |                        ^^^^^^^^^^^ expected struct `users::table`, found struct `SelectStatement`
    |
-   = note: expected type `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
-            found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>>, _>`
+   = note: expected struct `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
+              found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>>, _>`
    = note: required because of the requirements on the impl of `DistinctOnDsl<_>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>`
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>: Table` is not satisfied
@@ -100,8 +100,8 @@ error[E0271]: type mismatch resolving `<SelectStatement<FromClause<users::table>
 17 |     users.distinct_on(id).for_update();
    |                           ^^^^^^^^^^ expected struct `users::table`, found struct `SelectStatement`
    |
-   = note: expected type `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, DistinctOnClause<columns::id>>`
-            found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, DistinctOnClause<columns::id>>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, DistinctOnClause<columns::id>>>>, diesel::query_builder::distinct_clause::NoDistinctClause>`
+   = note: expected struct `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, DistinctOnClause<columns::id>>`
+              found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, DistinctOnClause<columns::id>>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, DistinctOnClause<columns::id>>>>, diesel::query_builder::distinct_clause::NoDistinctClause>`
    = note: required because of the requirements on the impl of `LockingDsl<diesel::query_builder::locking_clause::ForUpdate>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, DistinctOnClause<columns::id>>`
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, DistinctOnClause<columns::id>>: Table` is not satisfied
@@ -127,8 +127,8 @@ error[E0271]: type mismatch resolving `<SelectStatement<FromClause<users::table>
 19 |     users.for_update().group_by(id);
    |                        ^^^^^^^^ expected struct `users::table`, found struct `SelectStatement`
    |
-   = note: expected type `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
-            found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>>, _>`
+   = note: expected struct `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
+              found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>>, _>`
    = note: required because of the requirements on the impl of `GroupByDsl<_>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>`
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>: Table` is not satisfied
@@ -154,8 +154,8 @@ error[E0271]: type mismatch resolving `<SelectStatement<FromClause<users::table>
 20 |     users.group_by(id).for_update();
    |                        ^^^^^^^^^^ expected struct `users::table`, found struct `SelectStatement`
    |
-   = note: expected type `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
-            found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>>>>, _>`
+   = note: expected struct `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
+              found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>>>>, _>`
    = note: required because of the requirements on the impl of `LockingDsl<diesel::query_builder::locking_clause::ForUpdate>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>>`
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>>: Table` is not satisfied
@@ -181,8 +181,8 @@ error[E0271]: type mismatch resolving `<BoxedSelectStatement<'_, (diesel::sql_ty
 22 |     users.into_boxed().for_update();
    |                        ^^^^^^^^^^ expected struct `BoxedSelectStatement`, found struct `SelectStatement`
    |
-   = note: expected type `BoxedSelectStatement<'_, (diesel::sql_types::Integer,), FromClause<users::table>, _>`
-            found struct `SelectStatement<FromClause<BoxedSelectStatement<'_, (diesel::sql_types::Integer,), FromClause<users::table>, _>>>`
+   = note: expected struct `BoxedSelectStatement<'_, (diesel::sql_types::Integer,), FromClause<users::table>, _>`
+              found struct `SelectStatement<FromClause<BoxedSelectStatement<'_, (diesel::sql_types::Integer,), FromClause<users::table>, _>>>`
    = note: required because of the requirements on the impl of `LockingDsl<diesel::query_builder::locking_clause::ForUpdate>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer,), FromClause<users::table>, _>`
 
 error[E0277]: the trait bound `BoxedSelectStatement<'_, (diesel::sql_types::Integer,), FromClause<users::table>, _>: Table` is not satisfied
@@ -208,8 +208,8 @@ error[E0271]: type mismatch resolving `<SelectStatement<FromClause<users::table>
 23 |     users.for_update().into_boxed();
    |                        ^^^^^^^^^^ expected struct `users::table`, found struct `SelectStatement`
    |
-   = note: expected type `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
-            found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>>, _>`
+   = note: expected struct `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
+              found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>>, _>`
    = note: required because of the requirements on the impl of `BoxedDsl<'_, _>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>`
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>: Table` is not satisfied
@@ -237,8 +237,8 @@ error[E0271]: type mismatch resolving `<SelectStatement<FromClause<users::table>
 25 |     users.for_update().group_by(id).having(id.gt(1));
    |                        ^^^^^^^^ expected struct `users::table`, found struct `SelectStatement`
    |
-   = note: expected type `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
-            found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>>, _>`
+   = note: expected struct `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _>`
+              found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>>>, _>`
    = note: required because of the requirements on the impl of `GroupByDsl<_>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>`
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::NoGroupByClause, diesel::query_builder::having_clause::NoHavingClause, diesel::query_builder::locking_clause::LockingClause>: Table` is not satisfied
@@ -264,8 +264,8 @@ error[E0271]: type mismatch resolving `<SelectStatement<FromClause<users::table>
 26 |     users.group_by(id).having(id.gt(1)).for_update();
    |                                         ^^^^^^^^^^ expected struct `users::table`, found struct `SelectStatement`
    |
-   = note: expected type `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _, _>`
-            found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>, diesel::query_builder::having_clause::HavingClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Gt<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>, diesel::query_builder::having_clause::HavingClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Gt<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>>>, _, _>`
+   = note: expected struct `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, _, _>`
+              found struct `SelectStatement<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>, diesel::query_builder::having_clause::HavingClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Gt<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>, diesel::query_builder::having_clause::HavingClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Gt<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>>>, _, _>`
    = note: required because of the requirements on the impl of `LockingDsl<diesel::query_builder::locking_clause::ForUpdate>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>, diesel::query_builder::having_clause::HavingClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Gt<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>`
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<columns::id>, diesel::query_builder::having_clause::HavingClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Gt<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>: Table` is not satisfied
diff --git a/diesel_compile_tests/tests/fail/select_requires_valid_grouping.stderr b/diesel_compile_tests/tests/fail/select_requires_valid_grouping.stderr
index 74051871804c..8bde75ed07d2 100644
--- a/diesel_compile_tests/tests/fail/select_requires_valid_grouping.stderr
+++ b/diesel_compile_tests/tests/fail/select_requires_valid_grouping.stderr
@@ -61,7 +61,7 @@ error[E0277]: the trait bound `users::columns::id: IsContainedInGroupBy<comments
             and 2 others
     = note: required because of the requirements on the impl of `IsContainedInGroupBy<comments::columns::id>` for `(users::columns::id, posts::columns::id)`
     = note: required because of the requirements on the impl of `ValidGrouping<(users::columns::id, posts::columns::id)>` for `comments::columns::id`
-    = note: 1 redundant requirements hidden
+    = note: 2 redundant requirements hidden
     = note: required because of the requirements on the impl of `ValidGrouping<(users::columns::id, posts::columns::id)>` for `((users::columns::id, users::columns::name, users::columns::hair_color), (posts::columns::id, posts::columns::title, posts::columns::user_id), comments::columns::id)`
     = note: required because of the requirements on the impl of `SelectDsl<((users::columns::id, users::columns::name, users::columns::hair_color), (posts::columns::id, posts::columns::title, posts::columns::user_id), comments::columns::id)>` for `SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<posts::table, comments::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<comments::columns::post_id>, NullableExpression<posts::columns::id>>>>>>, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<posts::table, comments::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<comments::columns::post_id>, NullableExpression<posts::columns::id>>>>>>, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<(users::columns::id, posts::columns::id)>>`
 
@@ -77,8 +77,10 @@ error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy<comments
               <posts::columns::id as IsContainedInGroupBy<posts::columns::user_id>>
               <posts::columns::id as IsContainedInGroupBy<users::columns::hair_color>>
             and 2 others
+    = note: required because of the requirements on the impl of `IsContainedInGroupBy<comments::columns::id>` for `(posts::columns::id,)`
+    = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `IsContainedInGroupBy<comments::columns::id>` for `(users::columns::id, posts::columns::id)`
     = note: required because of the requirements on the impl of `ValidGrouping<(users::columns::id, posts::columns::id)>` for `comments::columns::id`
-    = note: 1 redundant requirements hidden
+    = note: 2 redundant requirements hidden
     = note: required because of the requirements on the impl of `ValidGrouping<(users::columns::id, posts::columns::id)>` for `((users::columns::id, users::columns::name, users::columns::hair_color), (posts::columns::id, posts::columns::title, posts::columns::user_id), comments::columns::id)`
     = note: required because of the requirements on the impl of `SelectDsl<((users::columns::id, users::columns::name, users::columns::hair_color), (posts::columns::id, posts::columns::title, posts::columns::user_id), comments::columns::id)>` for `SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<posts::table, comments::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<comments::columns::post_id>, NullableExpression<posts::columns::id>>>>>>, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<posts::table, comments::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<comments::columns::post_id>, NullableExpression<posts::columns::id>>>>>>, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<(users::columns::id, posts::columns::id)>>`
diff --git a/diesel_compile_tests/tests/fail/selectable.stderr b/diesel_compile_tests/tests/fail/selectable.stderr
index 810636588cf3..3c0bbd52e2b3 100644
--- a/diesel_compile_tests/tests/fail/selectable.stderr
+++ b/diesel_compile_tests/tests/fail/selectable.stderr
@@ -138,42 +138,10 @@ error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy<users::c
               <posts::columns::id as IsContainedInGroupBy<posts::columns::title>>
               <posts::columns::id as IsContainedInGroupBy<posts::columns::user_id>>
     = note: required because of the requirements on the impl of `ValidGrouping<posts::columns::id>` for `users::columns::name`
-    = note: 2 redundant requirements hidden
+    = note: 3 redundant requirements hidden
     = note: required because of the requirements on the impl of `ValidGrouping<posts::columns::id>` for `diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>`
     = note: required because of the requirements on the impl of `SelectDsl<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>` for `SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, posts::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, posts::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<posts::columns::id>>`
 
-error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy<users::columns::id>` is not satisfied
-   --> tests/fail/selectable.rs:158:10
-    |
-158 |         .load(&mut conn)
-    |          ^^^^ the trait `IsContainedInGroupBy<users::columns::id>` is not implemented for `posts::columns::id`
-    |
-    = help: the following implementations were found:
-              <posts::columns::id as IsContainedInGroupBy<posts::columns::id>>
-              <posts::columns::id as IsContainedInGroupBy<posts::columns::title>>
-              <posts::columns::id as IsContainedInGroupBy<posts::columns::user_id>>
-    = note: required because of the requirements on the impl of `ValidGrouping<posts::columns::id>` for `users::columns::id`
-    = note: 2 redundant requirements hidden
-    = note: required because of the requirements on the impl of `ValidGrouping<posts::columns::id>` for `diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>`
-    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, posts::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>, diesel::query_builder::select_clause::SelectClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<posts::columns::id>>`
-    = note: required because of the requirements on the impl of `LoadQuery<'_, _, UserWithEmbeddedPost>` for `SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, posts::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>, diesel::query_builder::select_clause::SelectClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<posts::columns::id>>`
-
-error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy<users::columns::name>` is not satisfied
-   --> tests/fail/selectable.rs:158:10
-    |
-158 |         .load(&mut conn)
-    |          ^^^^ the trait `IsContainedInGroupBy<users::columns::name>` is not implemented for `posts::columns::id`
-    |
-    = help: the following implementations were found:
-              <posts::columns::id as IsContainedInGroupBy<posts::columns::id>>
-              <posts::columns::id as IsContainedInGroupBy<posts::columns::title>>
-              <posts::columns::id as IsContainedInGroupBy<posts::columns::user_id>>
-    = note: required because of the requirements on the impl of `ValidGrouping<posts::columns::id>` for `users::columns::name`
-    = note: 2 redundant requirements hidden
-    = note: required because of the requirements on the impl of `ValidGrouping<posts::columns::id>` for `diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>`
-    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, posts::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>, diesel::query_builder::select_clause::SelectClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<posts::columns::id>>`
-    = note: required because of the requirements on the impl of `LoadQuery<'_, _, UserWithEmbeddedPost>` for `SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, posts::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>, diesel::query_builder::select_clause::SelectClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<posts::columns::id>>`
-
 error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggregates<diesel::expression::is_aggregate::Yes>` is not satisfied
    --> tests/fail/selectable.rs:164:10
     |
@@ -183,26 +151,11 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggreg
     = help: the following implementations were found:
               <diesel::expression::is_aggregate::No as MixedAggregates<diesel::expression::is_aggregate::Never>>
               <diesel::expression::is_aggregate::No as MixedAggregates<diesel::expression::is_aggregate::No>>
-    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(users::columns::id, users::columns::name, diesel::expression::count::count::count<diesel::sql_types::Integer, posts::columns::id>)`
-    = note: 1 redundant requirements hidden
+    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(users::columns::name, diesel::expression::count::count::count<diesel::sql_types::Integer, posts::columns::id>)`
+    = note: 2 redundant requirements hidden
     = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::expression::select_by::SelectBy<UserWithPostCount, Pg>`
     = note: required because of the requirements on the impl of `SelectDsl<diesel::expression::select_by::SelectBy<UserWithPostCount, Pg>>` for `SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, posts::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>>`
 
-error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggregates<diesel::expression::is_aggregate::Yes>` is not satisfied
-   --> tests/fail/selectable.rs:165:10
-    |
-165 |         .load(&mut conn)
-    |          ^^^^ the trait `MixedAggregates<diesel::expression::is_aggregate::Yes>` is not implemented for `diesel::expression::is_aggregate::No`
-    |
-    = help: the following implementations were found:
-              <diesel::expression::is_aggregate::No as MixedAggregates<diesel::expression::is_aggregate::Never>>
-              <diesel::expression::is_aggregate::No as MixedAggregates<diesel::expression::is_aggregate::No>>
-    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(users::columns::id, users::columns::name, diesel::expression::count::count::count<diesel::sql_types::Integer, posts::columns::id>)`
-    = note: 1 redundant requirements hidden
-    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::expression::select_by::SelectBy<UserWithPostCount, Pg>`
-    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, posts::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>, diesel::query_builder::select_clause::SelectClause<diesel::expression::select_by::SelectBy<UserWithPostCount, Pg>>>`
-    = note: required because of the requirements on the impl of `LoadQuery<'_, _, UserWithPostCount>` for `SelectStatement<FromClause<JoinOn<diesel::internal::table_macro::Join<users::table, posts::table, Inner>, diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<NullableExpression<posts::columns::user_id>, NullableExpression<users::columns::id>>>>>, diesel::query_builder::select_clause::SelectClause<diesel::expression::select_by::SelectBy<UserWithPostCount, Pg>>>`
-
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
    --> tests/fail/selectable.rs:172:10
     |
@@ -243,13 +196,24 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 172 |         .returning(UserWithEmbeddedPost::as_select())
     |          ^^^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
     |
-    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+   --> tests/fail/selectable.rs:12:1
+    |
+12  | / table! {
+13  | |     posts {
+14  | |         id -> Integer,
+15  | |         title -> Text,
+16  | |         user_id -> Integer,
+17  | |     }
+18  | | }
+    | |_^
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(posts::columns::id, posts::columns::title)`
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(posts::columns::id, posts::columns::title)`
     = note: 2 redundant requirements hidden
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>`
     = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, diesel::query_builder::insert_statement::ValuesClause<ColumnInsertValue<users::columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::private::Insert, diesel::query_builder::returning_clause::ReturningClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
    --> tests/fail/selectable.rs:173:10
@@ -293,7 +257,17 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 173 |         .load(&mut conn)
     |          ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
     |
-    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+   --> tests/fail/selectable.rs:12:1
+    |
+12  | / table! {
+13  | |     posts {
+14  | |         id -> Integer,
+15  | |         title -> Text,
+16  | |         user_id -> Integer,
+17  | |     }
+18  | | }
+    | |_^
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(posts::columns::id, posts::columns::title)`
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(posts::columns::id, posts::columns::title)`
@@ -301,6 +275,7 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>`
     = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, diesel::query_builder::insert_statement::ValuesClause<ColumnInsertValue<users::columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::private::Insert, diesel::query_builder::returning_clause::ReturningClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>>`
     = note: required because of the requirements on the impl of `LoadQuery<'_, _, UserWithEmbeddedPost>` for `InsertStatement<users::table, diesel::query_builder::insert_statement::ValuesClause<ColumnInsertValue<users::columns::name, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::private::Insert, diesel::query_builder::returning_clause::ReturningClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
    --> tests/fail/selectable.rs:180:10
@@ -342,13 +317,24 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 180 |         .returning(UserWithEmbeddedPost::as_select())
     |          ^^^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
     |
-    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+   --> tests/fail/selectable.rs:12:1
+    |
+12  | / table! {
+13  | |     posts {
+14  | |         id -> Integer,
+15  | |         title -> Text,
+16  | |         user_id -> Integer,
+17  | |     }
+18  | | }
+    | |_^
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(posts::columns::id, posts::columns::title)`
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(posts::columns::id, posts::columns::title)`
     = note: 2 redundant requirements hidden
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>`
     = note: required because of the requirements on the impl of `Query` for `UpdateStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::update_statement::changeset::Assign<diesel::query_builder::update_statement::changeset::ColumnWrapperForUpdate<users::columns::name>, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
    --> tests/fail/selectable.rs:181:10
@@ -392,7 +378,17 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 181 |         .load(&mut conn)
     |          ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
     |
-    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+   --> tests/fail/selectable.rs:12:1
+    |
+12  | / table! {
+13  | |     posts {
+14  | |         id -> Integer,
+15  | |         title -> Text,
+16  | |         user_id -> Integer,
+17  | |     }
+18  | | }
+    | |_^
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(posts::columns::id, posts::columns::title)`
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(posts::columns::id, posts::columns::title)`
@@ -400,6 +396,7 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>`
     = note: required because of the requirements on the impl of `Query` for `UpdateStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::update_statement::changeset::Assign<diesel::query_builder::update_statement::changeset::ColumnWrapperForUpdate<users::columns::name>, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>>`
     = note: required because of the requirements on the impl of `LoadQuery<'_, _, UserWithEmbeddedPost>` for `UpdateStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::update_statement::changeset::Assign<diesel::query_builder::update_statement::changeset::ColumnWrapperForUpdate<users::columns::name>, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
    --> tests/fail/selectable.rs:187:10
@@ -439,12 +436,23 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 187 |         .returning(UserWithEmbeddedPost::as_select())
     |          ^^^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
     |
-    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+   --> tests/fail/selectable.rs:12:1
+    |
+12  | / table! {
+13  | |     posts {
+14  | |         id -> Integer,
+15  | |         title -> Text,
+16  | |         user_id -> Integer,
+17  | |     }
+18  | | }
+    | |_^
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(posts::columns::id, posts::columns::title)`
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(posts::columns::id, posts::columns::title)`
     = note: 2 redundant requirements hidden
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>`
+    = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
    --> tests/fail/selectable.rs:188:10
@@ -488,7 +496,17 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 188 |         .load(&mut conn)
     |          ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
     |
-    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+   --> tests/fail/selectable.rs:12:1
+    |
+12  | / table! {
+13  | |     posts {
+14  | |         id -> Integer,
+15  | |         title -> Text,
+16  | |         user_id -> Integer,
+17  | |     }
+18  | | }
+    | |_^
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(posts::columns::id, posts::columns::title)`
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(posts::columns::id, posts::columns::title)`
@@ -496,6 +514,7 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
     = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>`
     = note: required because of the requirements on the impl of `Query` for `DeleteStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::returning_clause::ReturningClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>>`
     = note: required because of the requirements on the impl of `LoadQuery<'_, _, UserWithEmbeddedPost>` for `DeleteStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::returning_clause::ReturningClause<diesel::expression::select_by::SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0599]: the function or associated item `as_select` exists for struct `UserWithoutSelectable`, but its trait bounds were not satisfied
    --> tests/fail/selectable.rs:192:56
diff --git a/diesel_compile_tests/tests/fail/selecting_multiple_columns_requires_all_must_be_from_selectable_table.stderr b/diesel_compile_tests/tests/fail/selecting_multiple_columns_requires_all_must_be_from_selectable_table.stderr
index 6f2e3a12d10c..6916480d9bfc 100644
--- a/diesel_compile_tests/tests/fail/selecting_multiple_columns_requires_all_must_be_from_selectable_table.stderr
+++ b/diesel_compile_tests/tests/fail/selecting_multiple_columns_requires_all_must_be_from_selectable_table.stderr
@@ -34,11 +34,22 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 21 |     let stuff = users::table.select((posts::id, posts::user_id));
    |                              ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/selecting_multiple_columns_requires_all_must_be_from_selectable_table.rs:12:1
+   |
+12 | / table! {
+13 | |     posts {
+14 | |         id -> Integer,
+15 | |         title -> VarChar,
+16 | |         user_id -> Integer,
+17 | |     }
+18 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(posts::columns::id, posts::columns::user_id)`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(posts::columns::id, posts::columns::user_id)`
    = note: required because of the requirements on the impl of `SelectDsl<(posts::columns::id, posts::columns::user_id)>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/selecting_multiple_columns_requires_all_must_be_from_selectable_table.rs:21:30
@@ -47,11 +58,22 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |                              ^^^^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/selecting_multiple_columns_requires_all_must_be_from_selectable_table.rs:12:1
+   |
+12 | / table! {
+13 | |     posts {
+14 | |         id -> Integer,
+15 | |         title -> VarChar,
+16 | |         user_id -> Integer,
+17 | |     }
+18 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(posts::columns::id, posts::columns::user_id)`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(posts::columns::id, posts::columns::user_id)`
    = note: required because of the requirements on the impl of `SelectDsl<(posts::columns::id, posts::columns::user_id)>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
   --> tests/fail/selecting_multiple_columns_requires_all_must_be_from_selectable_table.rs:22:37
@@ -74,11 +96,22 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 22 |     let stuff = users::table.select((posts::id, users::name));
    |                              ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/selecting_multiple_columns_requires_all_must_be_from_selectable_table.rs:12:1
+   |
+12 | / table! {
+13 | |     posts {
+14 | |         id -> Integer,
+15 | |         title -> VarChar,
+16 | |         user_id -> Integer,
+17 | |     }
+18 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(posts::columns::id, users::columns::name)`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(posts::columns::id, users::columns::name)`
    = note: required because of the requirements on the impl of `SelectDsl<(posts::columns::id, users::columns::name)>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/selecting_multiple_columns_requires_all_must_be_from_selectable_table.rs:22:30
@@ -87,8 +120,19 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |                              ^^^^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/selecting_multiple_columns_requires_all_must_be_from_selectable_table.rs:12:1
+   |
+12 | / table! {
+13 | |     posts {
+14 | |         id -> Integer,
+15 | |         title -> VarChar,
+16 | |         user_id -> Integer,
+17 | |     }
+18 | | }
+   | |_^
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `(posts::columns::id, users::columns::name)`
    = note: required because of the requirements on the impl of `SelectableExpression<users::table>` for `(posts::columns::id, users::columns::name)`
    = note: required because of the requirements on the impl of `SelectDsl<(posts::columns::id, users::columns::name)>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.rs b/diesel_compile_tests/tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.rs
index 22a0df683bf7..20d72e0ad84e 100644
--- a/diesel_compile_tests/tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.rs
+++ b/diesel_compile_tests/tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.rs
@@ -1,7 +1,9 @@
 extern crate diesel;
 
 use diesel::prelude::*;
+use diesel::connection::{LoadConnection, DefaultLoadingMode};
 use diesel::sql_query;
+use diesel::pg::PgRowByRowLoadingMode;
 
 fn main() {
     let conn = &mut SqliteConnection::establish("foo").unwrap();
@@ -9,24 +11,29 @@ fn main() {
     // a statement, which is coupled to the connection itself
     // so we cannot have more than one iterator
     // for the same connection
-    let row_iter1 = conn.load(sql_query("bar")).unwrap();
-    let row_iter2 = conn.load(sql_query("bar")).unwrap();
+    let row_iter1 = LoadConnection::load(conn, sql_query("bar")).unwrap();
+    let row_iter2 = LoadConnection::load(conn, sql_query("bar")).unwrap();
 
     let _ = row_iter1.zip(row_iter2);
 
     let conn = &mut MysqlConnection::establish("foo").unwrap();
     // The same argument applies to mysql
-    let row_iter1 = conn.load(sql_query("bar")).unwrap();
-    let row_iter2 = conn.load(sql_query("bar")).unwrap();
+    let row_iter1 = LoadConnection::load(conn, sql_query("bar")).unwrap();
+    let row_iter2 = LoadConnection::load(conn, sql_query("bar")).unwrap();
 
     let _ = row_iter1.zip(row_iter2);
 
     let conn = &mut PgConnection::establish("foo").unwrap();
     // It works for PgConnection as the result is not related to the
     // connection in any way
-    let row_iter1 = conn.load(sql_query("bar")).unwrap();
-    let row_iter2 = conn.load(sql_query("bar")).unwrap();
+    let row_iter1 = LoadConnection::<DefaultLoadingMode>::load(conn, sql_query("bar")).unwrap();
+    let row_iter2 = LoadConnection::<DefaultLoadingMode>::load(conn, sql_query("bar")).unwrap();
 
     let _ = row_iter1.zip(row_iter2);
 
+    // It does not work for the libpq row by row mode
+    let row_iter1 = LoadConnection::<PgRowByRowLoadingMode>::load(conn, sql_query("bar")).unwrap();
+    let row_iter2 = LoadConnection::<PgRowByRowLoadingMode>::load(conn, sql_query("bar")).unwrap();
+
+    let _ = row_iter1.zip(row_iter2);
 }
diff --git a/diesel_compile_tests/tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.stderr b/diesel_compile_tests/tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.stderr
index 134d066cdbc4..ae381bf0b0a2 100644
--- a/diesel_compile_tests/tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.stderr
+++ b/diesel_compile_tests/tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.stderr
@@ -1,32 +1,32 @@
 error[E0499]: cannot borrow `*conn` as mutable more than once at a time
-  --> tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.rs:13:21
+  --> tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.rs:15:42
    |
-12 |     let row_iter1 = conn.load(sql_query("bar")).unwrap();
-   |                     ---- first mutable borrow occurs here
-13 |     let row_iter2 = conn.load(sql_query("bar")).unwrap();
-   |                     ^^^^ second mutable borrow occurs here
-14 |
-15 |     let _ = row_iter1.zip(row_iter2);
+14 |     let row_iter1 = LoadConnection::load(conn, sql_query("bar")).unwrap();
+   |                                          ---- first mutable borrow occurs here
+15 |     let row_iter2 = LoadConnection::load(conn, sql_query("bar")).unwrap();
+   |                                          ^^^^ second mutable borrow occurs here
+16 |
+17 |     let _ = row_iter1.zip(row_iter2);
    |             --------- first borrow later used here
 
 error[E0499]: cannot borrow `*conn` as mutable more than once at a time
-  --> tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.rs:20:21
+  --> tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.rs:22:42
    |
-19 |     let row_iter1 = conn.load(sql_query("bar")).unwrap();
-   |                     ---- first mutable borrow occurs here
-20 |     let row_iter2 = conn.load(sql_query("bar")).unwrap();
-   |                     ^^^^ second mutable borrow occurs here
-21 |
-22 |     let _ = row_iter1.zip(row_iter2);
+21 |     let row_iter1 = LoadConnection::load(conn, sql_query("bar")).unwrap();
+   |                                          ---- first mutable borrow occurs here
+22 |     let row_iter2 = LoadConnection::load(conn, sql_query("bar")).unwrap();
+   |                                          ^^^^ second mutable borrow occurs here
+23 |
+24 |     let _ = row_iter1.zip(row_iter2);
    |             --------- first borrow later used here
 
 error[E0499]: cannot borrow `*conn` as mutable more than once at a time
-  --> tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.rs:28:21
+  --> tests/fail/sqlite_and_mysql_do_not_allow_multiple_iterators.rs:36:67
    |
-27 |     let row_iter1 = conn.load(sql_query("bar")).unwrap();
-   |                     ---- first mutable borrow occurs here
-28 |     let row_iter2 = conn.load(sql_query("bar")).unwrap();
-   |                     ^^^^ second mutable borrow occurs here
-29 |
-30 |     let _ = row_iter1.zip(row_iter2);
+35 |     let row_iter1 = LoadConnection::<PgRowByRowLoadingMode>::load(conn, sql_query("bar")).unwrap();
+   |                                                                   ---- first mutable borrow occurs here
+36 |     let row_iter2 = LoadConnection::<PgRowByRowLoadingMode>::load(conn, sql_query("bar")).unwrap();
+   |                                                                   ^^^^ second mutable borrow occurs here
+37 |
+38 |     let _ = row_iter1.zip(row_iter2);
    |             --------- first borrow later used here
diff --git a/diesel_compile_tests/tests/fail/subselect_cannot_reference_random_tables.stderr b/diesel_compile_tests/tests/fail/subselect_cannot_reference_random_tables.stderr
index 9c96a2753780..cbc2c9f96843 100644
--- a/diesel_compile_tests/tests/fail/subselect_cannot_reference_random_tables.stderr
+++ b/diesel_compile_tests/tests/fail/subselect_cannot_reference_random_tables.stderr
@@ -18,7 +18,15 @@ error[E0271]: type mismatch resolving `<diesel::internal::table_macro::Join<post
 32 |         .load::<(i32,)>(&mut conn);
    |          ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>` for `comments::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>` for `comments::columns::id`
+  --> tests/fail/subselect_cannot_reference_random_tables.rs:17:1
+   |
+17 | / table! {
+18 | |     comments {
+19 | |         id -> Integer,
+20 | |     }
+21 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>`
@@ -27,6 +35,7 @@ error[E0271]: type mismatch resolving `<diesel::internal::table_macro::Join<post
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<users::table>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::array_comparison::In<users::columns::id, diesel::expression::subselect::Subselect<SelectStatement<FromClause<posts::table>, diesel::query_builder::select_clause::SelectClause<posts::columns::id>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>, diesel::sql_types::Integer>>>>`
    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::array_comparison::In<users::columns::id, diesel::expression::subselect::Subselect<SelectStatement<FromClause<posts::table>, diesel::query_builder::select_clause::SelectClause<posts::columns::id>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>, diesel::sql_types::Integer>>>>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, _, (i32,)>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::array_comparison::In<users::columns::id, diesel::expression::subselect::Subselect<SelectStatement<FromClause<posts::table>, diesel::query_builder::select_clause::SelectClause<posts::columns::id>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>, diesel::sql_types::Integer>>>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0271]: type mismatch resolving `<diesel::internal::table_macro::Join<posts::table, users::table, Inner> as AppearsInFromClause<comments::table>>::Count == diesel::query_source::Once`
   --> tests/fail/subselect_cannot_reference_random_tables.rs:38:10
@@ -34,7 +43,15 @@ error[E0271]: type mismatch resolving `<diesel::internal::table_macro::Join<post
 38 |         .load::<(i32,)>(&mut conn);
    |          ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>` for `comments::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>` for `comments::columns::id`
+  --> tests/fail/subselect_cannot_reference_random_tables.rs:17:1
+   |
+17 | / table! {
+18 | |     comments {
+19 | |         id -> Integer,
+20 | |     }
+21 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>`
@@ -43,6 +60,7 @@ error[E0271]: type mismatch resolving `<diesel::internal::table_macro::Join<post
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<users::table>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::id, diesel::pg::expression::array_comparison::Any<diesel::expression::subselect::Subselect<SelectStatement<FromClause<posts::table>, diesel::query_builder::select_clause::SelectClause<posts::columns::id>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>, Array<diesel::sql_types::Integer>>>>>>`
    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::id, diesel::pg::expression::array_comparison::Any<diesel::expression::subselect::Subselect<SelectStatement<FromClause<posts::table>, diesel::query_builder::select_clause::SelectClause<posts::columns::id>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>, Array<diesel::sql_types::Integer>>>>>>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, _, (i32,)>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::id, diesel::pg::expression::array_comparison::Any<diesel::expression::subselect::Subselect<SelectStatement<FromClause<posts::table>, diesel::query_builder::select_clause::SelectClause<posts::columns::id>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>, Array<diesel::sql_types::Integer>>>>>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0271]: type mismatch resolving `<diesel::internal::table_macro::Join<posts::table, users::table, Inner> as AppearsInFromClause<comments::table>>::Count == diesel::query_source::Once`
   --> tests/fail/subselect_cannot_reference_random_tables.rs:42:10
@@ -50,7 +68,15 @@ error[E0271]: type mismatch resolving `<diesel::internal::table_macro::Join<post
 42 |         .load::<(i32,)>(&mut conn);
    |          ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>` for `comments::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>` for `comments::columns::id`
+  --> tests/fail/subselect_cannot_reference_random_tables.rs:17:1
+   |
+17 | / table! {
+18 | |     comments {
+19 | |         id -> Integer,
+20 | |     }
+21 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<diesel::internal::table_macro::Join<posts::table, users::table, Inner>>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>`
@@ -59,3 +85,4 @@ error[E0271]: type mismatch resolving `<diesel::internal::table_macro::Join<post
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<users::table>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::exists::Exists<SelectStatement<FromClause<posts::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<posts::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>>>`
    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::exists::Exists<SelectStatement<FromClause<posts::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<posts::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>>>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, _, (i32,)>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::exists::Exists<SelectStatement<FromClause<posts::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<posts::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<comments::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/update_requires_column_be_from_same_table.stderr b/diesel_compile_tests/tests/fail/update_requires_column_be_from_same_table.stderr
index 01de68b45041..e8d40b3fb94c 100644
--- a/diesel_compile_tests/tests/fail/update_requires_column_be_from_same_table.stderr
+++ b/diesel_compile_tests/tests/fail/update_requires_column_be_from_same_table.stderr
@@ -10,8 +10,18 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 23 |     let command = update(users).set(name.eq(posts::title));
    |                                 ^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+  --> tests/fail/update_requires_column_be_from_same_table.rs:12:1
+   |
+12 | / table! {
+13 | |     posts {
+14 | |         id -> Integer,
+15 | |         title -> VarChar,
+16 | |     }
+17 | | }
+   | |_^
    = note: required because of the requirements on the impl of `AsChangeset` for `diesel::expression::operators::Eq<users::columns::name, posts::columns::title>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/update_requires_column_be_from_same_table.rs:23:33
@@ -20,5 +30,15 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |                                 ^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+  --> tests/fail/update_requires_column_be_from_same_table.rs:12:1
+   |
+12 | / table! {
+13 | |     posts {
+14 | |         id -> Integer,
+15 | |         title -> VarChar,
+16 | |     }
+17 | | }
+   | |_^
    = note: required because of the requirements on the impl of `AsChangeset` for `diesel::expression::operators::Eq<users::columns::name, posts::columns::title>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/update_requires_valid_where_clause.stderr b/diesel_compile_tests/tests/fail/update_requires_valid_where_clause.stderr
index d4b9eca601c8..8110c25f6fd2 100644
--- a/diesel_compile_tests/tests/fail/update_requires_valid_where_clause.stderr
+++ b/diesel_compile_tests/tests/fail/update_requires_valid_where_clause.stderr
@@ -4,13 +4,13 @@ error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel:
 21 |     update(users::table.filter(posts::id.eq(1)));
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoUpdateTarget` is not implemented for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>`
    |
-  ::: $DIESEL/src/query_builder/functions.rs
-   |
-   | pub fn update<T: IntoUpdateTarget>(source: T) -> UpdateStatement<T::Table, T::WhereClause> {
-   |                  ---------------- required by this bound in `diesel::update`
-   |
    = help: the following implementations were found:
              <SelectStatement<FromClause<F>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<F>>, diesel::query_builder::distinct_clause::NoDistinctClause, W> as IntoUpdateTarget>
+note: required by a bound in `diesel::update`
+  --> $DIESEL/src/query_builder/functions.rs
+   |
+   | pub fn update<T: IntoUpdateTarget>(source: T) -> UpdateStatement<T::Table, T::WhereClause> {
+   |                  ^^^^^^^^^^^^^^^^ required by this bound in `diesel::update`
 
 error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Once`
   --> tests/fail/update_requires_valid_where_clause.rs:23:26
@@ -18,10 +18,19 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 23 |     update(users::table).filter(posts::id.eq(1));
    |                          ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/update_requires_valid_where_clause.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
    = note: required because of the requirements on the impl of `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>` for `UpdateStatement<users::table, diesel::query_builder::where_clause::NoWhereClause>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/update_requires_valid_where_clause.rs:23:26
@@ -30,10 +39,19 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |                          ^^^^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/update_requires_valid_where_clause.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
    = note: required because of the requirements on the impl of `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>` for `UpdateStatement<users::table, diesel::query_builder::where_clause::NoWhereClause>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Once`
   --> tests/fail/update_requires_valid_where_clause.rs:26:10
@@ -41,10 +59,19 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 26 |         .filter(posts::id.eq(1));
    |          ^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/update_requires_valid_where_clause.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
    = note: required because of the requirements on the impl of `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>` for `UpdateStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::update_statement::changeset::Assign<diesel::query_builder::update_statement::changeset::ColumnWrapperForUpdate<users::columns::id>, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/update_requires_valid_where_clause.rs:26:10
@@ -53,10 +80,19 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |          ^^^^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::id`
+  --> tests/fail/update_requires_valid_where_clause.rs:11:1
+   |
+11 | / table! {
+12 | |     posts {
+13 | |         id -> Integer,
+14 | |     }
+15 | | }
+   | |_^
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
    = note: required because of the requirements on the impl of `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>` for `UpdateStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::update_statement::changeset::Assign<diesel::query_builder::update_statement::changeset::ColumnWrapperForUpdate<users::columns::id>, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<posts::columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>>: IntoUpdateTarget` is not satisfied
   --> tests/fail/update_requires_valid_where_clause.rs:21:5
diff --git a/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr b/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr
index 6651a5a4fdd3..064735246522 100644
--- a/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr
+++ b/diesel_compile_tests/tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.stderr
@@ -1,25 +1,27 @@
-error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
+error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>: QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not satisfied
   --> tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.rs:18:10
    |
 18 |         .get_result(&mut connection);
-   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
    |
    = help: the following implementations were found:
-             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, backend::sql_dialect::returning_clause::PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, sqlite::backend::SqliteReturningClause>>
              <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB>>
    = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `UpdateStatement<users::table, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<diesel::query_builder::update_statement::changeset::ColumnWrapperForUpdate<columns::name>, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, diesel::SqliteConnection, _>` for `UpdateStatement<users::table, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<diesel::query_builder::update_statement::changeset::ColumnWrapperForUpdate<columns::name>, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Text, &str>>>`
 
-error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<columns::name>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
+error[E0277]: the trait bound `diesel::query_builder::returning_clause::ReturningClause<columns::name>: QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not satisfied
   --> tests/fail/update_statement_does_not_support_returning_methods_on_sqlite.rs:23:10
    |
 23 |         .get_result(&mut connection);
-   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, backend::sql_dialect::returning_clause::DoesNotSupportReturningClause>` is not implemented for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
    |
    = help: the following implementations were found:
-             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, backend::sql_dialect::returning_clause::PgLikeReturningClause>>
+             <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB, sqlite::backend::SqliteReturningClause>>
              <diesel::query_builder::returning_clause::ReturningClause<Expr> as QueryFragment<DB>>
    = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
    = note: 1 redundant requirements hidden
diff --git a/diesel_compile_tests/tests/fail/upsert_with_multiple_values_not_supported_on_sqlite.stderr b/diesel_compile_tests/tests/fail/upsert_with_multiple_values_not_supported_on_sqlite.stderr
index 45ccbcfbc5fd..d2a4fd7f0d4f 100644
--- a/diesel_compile_tests/tests/fail/upsert_with_multiple_values_not_supported_on_sqlite.stderr
+++ b/diesel_compile_tests/tests/fail/upsert_with_multiple_values_not_supported_on_sqlite.stderr
@@ -6,17 +6,17 @@ error[E0277]: the trait bound `diesel::query_builder::insert_statement::batch_in
    |
    = help: the following implementations were found:
              <diesel::query_builder::insert_statement::batch_insert::BatchInsert<V, Tab, QId, HAS_STATIC_QUERY_ID> as QueryFragment<DB>>
-             <diesel::query_builder::insert_statement::batch_insert::BatchInsert<Vec<diesel::query_builder::insert_statement::ValuesClause<V, Tab>>, Tab, QId, HAS_STATIC_QUERY_ID> as QueryFragment<DB, PostgresLikeBatchInsertSupport>>
+             <diesel::query_builder::insert_statement::batch_insert::BatchInsert<Vec<diesel::query_builder::insert_statement::ValuesClause<V, Tab>>, Tab, QId, HAS_STATIC_QUERY_ID> as QueryFragment<DB, backend::sql_dialect::batch_insert_support::PostgresLikeBatchInsertSupport>>
    = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::insert_statement::batch_insert::BatchInsert<Vec<diesel::query_builder::insert_statement::ValuesClause<ColumnInsertValue<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>, users::table>>, users::table, (), false>`
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `InsertStatement<users::table, diesel::query_builder::upsert::on_conflict_clause::OnConflictValues<diesel::query_builder::insert_statement::batch_insert::BatchInsert<Vec<diesel::query_builder::insert_statement::ValuesClause<ColumnInsertValue<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>, users::table>>, users::table, (), false>, diesel::query_builder::upsert::on_conflict_target::NoConflictTarget, diesel::query_builder::upsert::on_conflict_actions::DoNothing>>`
    = note: required because of the requirements on the impl of `ExecuteDsl<diesel::SqliteConnection, Sqlite>` for `InsertStatement<users::table, diesel::query_builder::upsert::on_conflict_clause::OnConflictValues<diesel::query_builder::insert_statement::batch_insert::BatchInsert<Vec<diesel::query_builder::insert_statement::ValuesClause<ColumnInsertValue<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>, users::table>>, users::table, (), false>, diesel::query_builder::upsert::on_conflict_target::NoConflictTarget, diesel::query_builder::upsert::on_conflict_actions::DoNothing>>`
 
-error[E0271]: type mismatch resolving `<Sqlite as SqlDialect>::InsertWithDefaultKeyword == IsoSqlDefaultKeyword`
+error[E0271]: type mismatch resolving `<Sqlite as SqlDialect>::InsertWithDefaultKeyword == backend::sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword`
   --> tests/fail/upsert_with_multiple_values_not_supported_on_sqlite.rs:17:10
    |
 17 |         .execute(&mut connection);
-   |          ^^^^^^^ expected struct `DoesNotSupportDefaultKeyword`, found struct `IsoSqlDefaultKeyword`
+   |          ^^^^^^^ expected struct `backend::sql_dialect::default_keyword_for_insert::DoesNotSupportDefaultKeyword`, found struct `backend::sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword`
    |
    = note: required because of the requirements on the impl of `CanInsertInSingleQuery<Sqlite>` for `diesel::query_builder::insert_statement::batch_insert::BatchInsert<Vec<diesel::query_builder::insert_statement::ValuesClause<ColumnInsertValue<columns::id, diesel::internal::derives::as_expression::Bound<diesel::sql_types::Integer, i32>>, users::table>>, users::table, (), false>`
    = note: 1 redundant requirements hidden
diff --git a/diesel_compile_tests/tests/fail/user_defined_functions_follow_same_selection_rules.stderr b/diesel_compile_tests/tests/fail/user_defined_functions_follow_same_selection_rules.stderr
index 1a4bf41d77d5..188ac616c7c7 100644
--- a/diesel_compile_tests/tests/fail/user_defined_functions_follow_same_selection_rules.stderr
+++ b/diesel_compile_tests/tests/fail/user_defined_functions_follow_same_selection_rules.stderr
@@ -12,12 +12,22 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
 38 |         .load::<User>(&mut conn);
    |          ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
    |
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+  --> tests/fail/user_defined_functions_follow_same_selection_rules.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |         title -> VarChar,
+17 | |     }
+18 | | }
+   | |_^
    = note: 3 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, bar::bar<posts::columns::title>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<users::table>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, bar::bar<posts::columns::title>>>>`
    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, bar::bar<posts::columns::title>>>>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, _, User>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, bar::bar<posts::columns::title>>>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not satisfied
   --> tests/fail/user_defined_functions_follow_same_selection_rules.rs:38:10
@@ -26,9 +36,19 @@ error[E0277]: the trait bound `users::table: TableNotEqual<posts::table>` is not
    |          ^^^^ the trait `TableNotEqual<posts::table>` is not implemented for `users::table`
    |
    = note: required because of the requirements on the impl of `AppearsInFromClause<posts::table>` for `users::table`
-   = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `posts::columns::title`
+  --> tests/fail/user_defined_functions_follow_same_selection_rules.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |         title -> VarChar,
+17 | |     }
+18 | | }
+   | |_^
    = note: 3 redundant requirements hidden
    = note: required because of the requirements on the impl of `AppearsOnTable<users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, bar::bar<posts::columns::title>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<FromClause<users::table>>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, bar::bar<posts::columns::title>>>>`
    = note: required because of the requirements on the impl of `Query` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, bar::bar<posts::columns::title>>>>>`
    = note: required because of the requirements on the impl of `LoadQuery<'_, _, User>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::name, bar::bar<posts::columns::title>>>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_derives/tests/as_changeset.rs b/diesel_derives/tests/as_changeset.rs
index 33057d9f8291..e366863a933e 100644
--- a/diesel_derives/tests/as_changeset.rs
+++ b/diesel_derives/tests/as_changeset.rs
@@ -1,3 +1,5 @@
+use diesel::deserialize::FromSqlRow;
+use diesel::expression::AsExpression;
 use diesel::*;
 use helpers::*;
 use schema::*;
@@ -224,9 +226,9 @@ fn with_serialize_as() {
     #[diesel(sql_type = sql_types::Text)]
     struct UppercaseString(pub String);
 
-    impl Into<UppercaseString> for String {
-        fn into(self) -> UppercaseString {
-            UppercaseString(self.to_uppercase())
+    impl From<String> for UppercaseString {
+        fn from(val: String) -> Self {
+            UppercaseString(val.to_uppercase())
         }
     }
 
diff --git a/diesel_derives/tests/queryable_by_name.rs b/diesel_derives/tests/queryable_by_name.rs
index e070e3a5ae24..9ccecffca622 100644
--- a/diesel_derives/tests/queryable_by_name.rs
+++ b/diesel_derives/tests/queryable_by_name.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::blacklisted_name)]
 use diesel::sql_types::Integer;
 use diesel::*;
 
diff --git a/diesel_derives/tests/selectable.rs b/diesel_derives/tests/selectable.rs
index 5174b5e5ca7f..76272cdcbf94 100644
--- a/diesel_derives/tests/selectable.rs
+++ b/diesel_derives/tests/selectable.rs
@@ -86,3 +86,31 @@ fn embedded_option() {
     let data = my_structs::table.select(A::as_select()).get_result(conn);
     assert!(data.is_err());
 }
+
+#[test]
+fn embedded_option_with_nullable_field() {
+    table! {
+        my_structs (foo) {
+            foo -> Integer,
+            bar -> Nullable<Integer>,
+        }
+    }
+
+    #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Selectable)]
+    #[diesel(table_name = my_structs)]
+    struct A {
+        foo: i32,
+        #[diesel(embed)]
+        b: Option<B>,
+    }
+
+    #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Selectable)]
+    #[diesel(table_name = my_structs)]
+    struct B {
+        bar: Option<i32>,
+    }
+
+    let conn = &mut connection();
+    let data = my_structs::table.select(A::as_select()).get_result(conn);
+    assert!(data.is_err());
+}
diff --git a/diesel_derives/tests/tests.rs b/diesel_derives/tests/tests.rs
index 0d09bf99ab2e..91a99948a645 100644
--- a/diesel_derives/tests/tests.rs
+++ b/diesel_derives/tests/tests.rs
@@ -1,5 +1,3 @@
-#![deny(warnings)]
-
 #[macro_use]
 extern crate cfg_if;
 #[macro_use]
diff --git a/diesel_tests/Cargo.toml b/diesel_tests/Cargo.toml
index 588225e428ae..c9206f559ebc 100644
--- a/diesel_tests/Cargo.toml
+++ b/diesel_tests/Cargo.toml
@@ -10,16 +10,17 @@ edition = "2018"
 [dependencies]
 assert_matches = "1.0.1"
 chrono = { version = "0.4.19", default-features = false, features = ["clock", "std"] }
-diesel = { path = "../diesel", default-features = false, features = ["quickcheck", "chrono", "uuid", "serde_json", "network-address", "numeric", "with-deprecated"] }
+diesel = { path = "../diesel", default-features = false, features = ["quickcheck", "chrono", "uuid", "serde_json", "ipnet-address", "network-address", "numeric", "with-deprecated"] }
 diesel_migrations = { path = "../diesel_migrations" }
 dotenvy = "0.15"
 quickcheck = "1.0.3"
-uuid = { version = ">=0.7.0, <2.0.0" }
+uuid = { version = "1.0.0" }
 serde_json = { version=">=0.9, <2.0" }
-ipnetwork = ">=0.12.2, <0.19.0"
+ipnet = { version = "2.5.0" }
+ipnetwork = ">=0.12.2, <0.21.0"
 bigdecimal = ">= 0.0.13, < 0.4.0"
 rand = "0.8.4"
-libsqlite3-sys = { version = "0.24", optional = true }
+libsqlite3-sys = { version = "0.25", optional = true }
 
 [features]
 default = []
diff --git a/diesel_tests/tests/annotations.rs b/diesel_tests/tests/annotations.rs
index d614af850d2e..7eb2caebc67b 100644
--- a/diesel_tests/tests/annotations.rs
+++ b/diesel_tests/tests/annotations.rs
@@ -50,9 +50,10 @@ fn association_where_parent_and_child_have_underscores() {
     }
 
     impl SpecialPost {
+        #[allow(clippy::new_ret_no_self)]
         fn new(user_id: i32, title: &str) -> NewSpecialPost {
             NewSpecialPost {
-                user_id: user_id,
+                user_id,
                 title: title.to_owned(),
             }
         }
@@ -66,10 +67,9 @@ fn association_where_parent_and_child_have_underscores() {
     }
 
     impl SpecialComment {
+        #[allow(clippy::new_ret_no_self)]
         fn new(special_post_id: i32) -> NewSpecialComment {
-            NewSpecialComment {
-                special_post_id: special_post_id,
-            }
+            NewSpecialComment { special_post_id }
         }
     }
 
diff --git a/diesel_tests/tests/associations.rs b/diesel_tests/tests/associations.rs
index 4079f63d446c..fa204ce0ec8d 100644
--- a/diesel_tests/tests/associations.rs
+++ b/diesel_tests/tests/associations.rs
@@ -134,7 +134,7 @@ fn grouping_associations_maintains_ordering() {
     assert_eq!(expected_data, users_and_posts);
 
     // Test when sorted manually
-    let users = vec![sean.clone(), tess.clone()];
+    let users = vec![sean, tess];
     let mut posts = Post::belonging_to(&users)
         .load::<Post>(&mut connection)
         .unwrap();
diff --git a/diesel_tests/tests/boxed_queries.rs b/diesel_tests/tests/boxed_queries.rs
index 1f5f838bc796..2805342dc95d 100644
--- a/diesel_tests/tests/boxed_queries.rs
+++ b/diesel_tests/tests/boxed_queries.rs
@@ -54,11 +54,11 @@ fn boxed_queries_can_differ_conditionally() {
     assert_eq!(Ok(expected_data), all);
 
     let ordered = source(Query::Ordered).load(connection);
-    let expected_data = vec![tess.clone(), sean.clone(), jim.clone()];
+    let expected_data = vec![tess, sean.clone(), jim];
     assert_eq!(Ok(expected_data), ordered);
 
     let one = source(Query::One).load(connection);
-    let expected_data = vec![sean.clone()];
+    let expected_data = vec![sean];
     assert_eq!(Ok(expected_data), one);
 }
 
diff --git a/diesel_tests/tests/combination.rs b/diesel_tests/tests/combination.rs
index 04893e26535b..262fcde7ebb5 100644
--- a/diesel_tests/tests/combination.rs
+++ b/diesel_tests/tests/combination.rs
@@ -116,3 +116,33 @@ fn except() {
         .unwrap();
     assert_eq!(expected_data, data);
 }
+
+#[test]
+fn union_with_order() {
+    let conn = &mut connection();
+    let data = vec![
+        NewUser::new("Sean", None),
+        NewUser::new("Tess", None),
+        NewUser::new("Jim", None),
+    ];
+    insert_into(users::table)
+        .values(&data)
+        .execute(conn)
+        .unwrap();
+
+    let users = users::table
+        .select(users::name)
+        .order_by(users::id.asc())
+        .limit(1)
+        .union(
+            users::table
+                .order_by(users::id.desc())
+                .select(users::name)
+                .limit(1),
+        )
+        .positional_order_by(1)
+        .load::<String>(conn)
+        .unwrap();
+
+    assert_eq!(vec![String::from("Jim"), "Sean".into()], users);
+}
diff --git a/diesel_tests/tests/distinct.rs b/diesel_tests/tests/distinct.rs
index ab2f99ecf3db..ccbc28c9cb2c 100644
--- a/diesel_tests/tests/distinct.rs
+++ b/diesel_tests/tests/distinct.rs
@@ -32,13 +32,30 @@ fn distinct_on() {
         .select((name, hair_color))
         .order(name)
         .distinct_on(name);
-    let expected_data = vec![
+    let mut expected_data = vec![
         ("Sean".to_string(), Some("black".to_string())),
         ("Tess".to_string(), None),
     ];
     let data: Vec<_> = source.load(connection).unwrap();
 
     assert_eq!(expected_data, data);
+
+    let source = users
+        .select((name, hair_color))
+        .order(name.asc())
+        .distinct_on(name);
+    let data: Vec<_> = source.load(connection).unwrap();
+
+    assert_eq!(expected_data, data);
+
+    let source = users
+        .select((name, hair_color))
+        .order(name.desc())
+        .distinct_on(name);
+    let data: Vec<_> = source.load(connection).unwrap();
+
+    expected_data.reverse();
+    assert_eq!(expected_data, data);
 }
 
 #[cfg(feature = "postgres")]
diff --git a/diesel_tests/tests/errors.rs b/diesel_tests/tests/errors.rs
index fb3ab6fb5a7c..4a683e34fc54 100644
--- a/diesel_tests/tests/errors.rs
+++ b/diesel_tests/tests/errors.rs
@@ -106,9 +106,11 @@ fn foreign_key_violation_correct_constraint_name() {
 
 #[test]
 #[cfg(feature = "postgres")]
+// This is a false positive as there is a side effect of this collect (spawning threads)
+#[allow(clippy::needless_collect)]
 fn isolation_errors_are_detected() {
     use diesel::result::DatabaseErrorKind::SerializationFailure;
-    use diesel::result::Error::{CommitTransactionFailed, DatabaseError};
+    use diesel::result::Error::DatabaseError;
     use std::sync::{Arc, Barrier};
     use std::thread;
 
@@ -180,11 +182,7 @@ fn isolation_errors_are_detected() {
     results.sort_by_key(|r| r.is_err());
 
     assert_matches!(results[0], Ok(_));
-    assert_matches!(results[1],
-                    Err(CommitTransactionFailed { ref commit_error, ..})
-                    if matches!(
-                        &** commit_error,
-                        DatabaseError(SerializationFailure, _)));
+    assert_matches!(results[1], Err(DatabaseError(SerializationFailure, _)));
 }
 
 #[test]
diff --git a/diesel_tests/tests/expressions/ops.rs b/diesel_tests/tests/expressions/ops.rs
index 3019466344f6..3a82564c6826 100644
--- a/diesel_tests/tests/expressions/ops.rs
+++ b/diesel_tests/tests/expressions/ops.rs
@@ -116,6 +116,8 @@ fn test_adding_nullables() {
 }
 
 #[test]
+#[allow(clippy::eq_op)]
+// As this creates a sql expression clippy is wrong here
 fn test_subtracting_nullables() {
     use crate::schema::nullable_table::dsl::*;
     let connection = &mut connection_with_nullable_table_data();
@@ -156,6 +158,8 @@ fn test_multiplying_nullables() {
 }
 
 #[test]
+#[allow(clippy::eq_op)]
+// As this creates a sql expression clippy is wrong here
 fn test_dividing_nullables() {
     use crate::schema::nullable_table::dsl::*;
     let connection = &mut connection_with_nullable_table_data();
@@ -205,8 +209,8 @@ fn precedence_with_parens_is_maintained() {
 fn test_adding_unsigned() {
     use crate::schema::unsigned_table::dsl::*;
     let connection = &mut connection();
-    connection
-        .execute("INSERT INTO unsigned_table VALUES (1,1), (2,2)")
+    diesel::sql_query("INSERT INTO unsigned_table VALUES (1,1), (2,2)")
+        .execute(connection)
         .unwrap();
 
     let expected_data = vec![2, 3];
@@ -220,11 +224,13 @@ fn test_adding_unsigned() {
 
 #[test]
 #[cfg(feature = "mysql")]
+#[allow(clippy::eq_op)]
+// As this creates a sql expression clippy is wrong here
 fn test_subtracting_unsigned() {
     use crate::schema::unsigned_table::dsl::*;
     let connection = &mut connection();
-    connection
-        .execute("INSERT INTO unsigned_table VALUES (1,1), (2,2)")
+    diesel::sql_query("INSERT INTO unsigned_table VALUES (1,1), (2,2)")
+        .execute(connection)
         .unwrap();
 
     let expected_data = vec![0, 1];
@@ -238,11 +244,13 @@ fn test_subtracting_unsigned() {
 
 #[test]
 #[cfg(feature = "mysql")]
+#[allow(clippy::identity_op)]
+// As this creates a sql expression clippy is wrong here
 fn test_multiplying_unsigned() {
     use crate::schema::unsigned_table::dsl::*;
     let connection = &mut connection();
-    connection
-        .execute("INSERT INTO unsigned_table VALUES (1,1), (2,2)")
+    diesel::sql_query("INSERT INTO unsigned_table VALUES (1,1), (2,2)")
+        .execute(connection)
         .unwrap();
 
     let expected_data = vec![1, 2];
@@ -256,11 +264,13 @@ fn test_multiplying_unsigned() {
 
 #[test]
 #[cfg(feature = "mysql")]
+#[allow(clippy::identity_op, clippy::eq_op)]
+// As this creates a sql expression clippy is wrong here
 fn test_dividing_unsigned() {
     use crate::schema::unsigned_table::dsl::*;
     let connection = &mut connection();
-    connection
-        .execute("INSERT INTO unsigned_table VALUES (1,1), (2,2)")
+    diesel::sql_query("INSERT INTO unsigned_table VALUES (1,1), (2,2)")
+        .execute(connection)
         .unwrap();
 
     let expected_data = vec![1, 2];
@@ -277,8 +287,8 @@ fn test_dividing_unsigned() {
 fn test_multiple_unsigned() {
     use crate::schema::unsigned_table::dsl::*;
     let connection = &mut connection();
-    connection
-        .execute("INSERT INTO unsigned_table VALUES (1,1), (2,2)")
+    diesel::sql_query("INSERT INTO unsigned_table VALUES (1,1), (2,2)")
+        .execute(connection)
         .unwrap();
 
     let expected_data = vec![1, 1];
diff --git a/diesel_tests/tests/insert.rs b/diesel_tests/tests/insert.rs
index 68a5a8d5d05f..5c842801436e 100644
--- a/diesel_tests/tests/insert.rs
+++ b/diesel_tests/tests/insert.rs
@@ -171,6 +171,53 @@ fn insert_record_using_returning_clause() {
     assert_eq!(expected_user, inserted_user);
 }
 
+#[test]
+#[cfg(all(feature = "sqlite", feature = "returning_clauses_for_sqlite_3_35"))]
+fn insert_record_attached_database_using_returning_clause() {
+    table! {
+        external.external_table (id) {
+            id -> Integer,
+            data -> Text,
+        }
+    }
+
+    #[derive(Queryable, Debug, PartialEq)]
+    #[diesel(table_name = external_table)]
+    struct ExternalEntity {
+        id: i32,
+        data: String,
+    }
+
+    let connection = &mut connection_without_transaction();
+
+    // Create external table
+    diesel::sql_query("ATTACH DATABASE ':memory:' AS external")
+        .execute(connection)
+        .unwrap();
+    diesel::sql_query(
+        r#"
+        CREATE TABLE external.external_table (
+            id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+            data text NOT NULL
+        )
+    "#,
+    )
+    .execute(connection)
+    .unwrap();
+
+    // Insert entity and fetch with the returning clause
+    let inserted_entity = insert_into(external_table::table)
+        .values(external_table::data.eq("test".to_string()))
+        .get_result::<ExternalEntity>(connection)
+        .unwrap();
+    let expected_entity = ExternalEntity {
+        id: inserted_entity.id,
+        data: "test".to_string(),
+    };
+
+    assert_eq!(expected_entity, inserted_entity);
+}
+
 #[test]
 #[cfg(not(any(feature = "sqlite", feature = "mysql")))]
 fn insert_records_using_returning_clause() {
diff --git a/diesel_tests/tests/internal_details.rs b/diesel_tests/tests/internal_details.rs
index 80f3cc33d7d0..d881c0291107 100644
--- a/diesel_tests/tests/internal_details.rs
+++ b/diesel_tests/tests/internal_details.rs
@@ -54,14 +54,15 @@ fn empty_query_gives_proper_error_instead_of_panicking() {
 
 #[test]
 fn ensure_sqlite_does_not_access_dropped_buffers() {
+    use diesel::connection::{DefaultLoadingMode, LoadConnection};
     let connection = &mut connection();
 
     let buf: Vec<u8> = vec![0, 1, 2];
 
     let query = diesel::select((&buf as &[u8]).into_sql::<sql_types::Binary>());
 
-    let mut iter = Connection::load(connection, query).unwrap();
+    let mut iter = LoadConnection::<DefaultLoadingMode>::load(connection, query).unwrap();
 
-    assert_eq!(iter.next().is_some(), true);
-    assert_eq!(iter.next().is_none(), true);
+    assert!(iter.next().is_some());
+    assert!(iter.next().is_none());
 }
diff --git a/diesel_tests/tests/joins.rs b/diesel_tests/tests/joins.rs
index f56e4e0c2a3e..bc4a447c480d 100644
--- a/diesel_tests/tests/joins.rs
+++ b/diesel_tests/tests/joins.rs
@@ -301,6 +301,7 @@ fn select_right_side_with_nullable_column_first() {
 }
 
 #[test]
+#[allow(clippy::type_complexity)]
 fn select_left_join_right_side_with_non_null_inside() {
     let connection = &mut connection_with_sean_and_tess_in_users_table();
 
@@ -467,7 +468,7 @@ fn selecting_parent_child_grandchild() {
         (sean.clone(), (posts[0].clone(), comments[2].clone())),
         (sean.clone(), (posts[2].clone(), comments[1].clone())),
     ];
-    assert_eq!(Ok(expected.clone()), data);
+    assert_eq!(Ok(expected), data);
 
     let data = users::table
         .inner_join(
@@ -523,8 +524,8 @@ fn selecting_parent_child_grandchild() {
     let expected = vec![
         (sean.clone(), Some((posts[0].clone(), comments[0].clone()))),
         (sean.clone(), Some((posts[0].clone(), comments[2].clone()))),
-        (sean.clone(), Some((posts[2].clone(), comments[1].clone()))),
-        (tess.clone(), None),
+        (sean, Some((posts[2].clone(), comments[1].clone()))),
+        (tess, None),
     ];
     assert_eq!(Ok(expected), data);
 }
@@ -546,7 +547,7 @@ fn selecting_grandchild_child_parent() {
     let expected = vec![
         (comments[0].clone(), (posts[0].clone(), sean.clone())),
         (comments[2].clone(), (posts[0].clone(), sean.clone())),
-        (comments[1].clone(), (posts[2].clone(), sean.clone())),
+        (comments[1].clone(), (posts[2].clone(), sean)),
     ];
     assert_eq!(Ok(expected), data);
 }
@@ -568,7 +569,7 @@ fn selecting_four_tables_deep() {
         .load(&mut connection);
     let expected = vec![(
         sean.clone(),
-        (posts[0].clone(), (comments[0].clone(), likes[0].clone())),
+        (posts[0].clone(), (comments[0].clone(), likes[0])),
     )];
     assert_eq!(Ok(expected), data);
 
@@ -579,19 +580,13 @@ fn selecting_four_tables_deep() {
     let expected = vec![
         (
             sean.clone(),
-            (
-                posts[0].clone(),
-                (comments[0].clone(), Some(likes[0].clone())),
-            ),
+            (posts[0].clone(), (comments[0].clone(), Some(likes[0]))),
         ),
         (
             sean.clone(),
             (posts[0].clone(), (comments[2].clone(), None)),
         ),
-        (
-            sean.clone(),
-            (posts[2].clone(), (comments[1].clone(), None)),
-        ),
+        (sean, (posts[2].clone(), (comments[1].clone(), None))),
     ];
     assert_eq!(Ok(expected), data);
 }
@@ -611,7 +606,7 @@ fn selecting_parent_child_sibling() {
         .inner_join(posts::table)
         .inner_join(likes::table)
         .load(&mut connection);
-    let expected = vec![(tess.clone(), posts[1].clone(), likes[0].clone())];
+    let expected = vec![(tess.clone(), posts[1].clone(), likes[0])];
     assert_eq!(Ok(expected), data);
 
     let data = users::table
@@ -621,8 +616,8 @@ fn selecting_parent_child_sibling() {
         .load(&mut connection);
     let expected = vec![
         (sean.clone(), posts[0].clone(), None),
-        (sean.clone(), posts[2].clone(), None),
-        (tess.clone(), posts[1].clone(), Some(likes[0].clone())),
+        (sean, posts[2].clone(), None),
+        (tess, posts[1].clone(), Some(likes[0])),
     ];
     assert_eq!(Ok(expected), data);
 }
@@ -653,7 +648,7 @@ fn selecting_crazy_nested_joins() {
             sean.clone(),
             (
                 posts[0].clone(),
-                Some((comments[0].clone(), Some(likes[0].clone()))),
+                Some((comments[0].clone(), Some(likes[0]))),
                 None,
             ),
         ),
@@ -665,10 +660,7 @@ fn selecting_crazy_nested_joins() {
             sean.clone(),
             (posts[2].clone(), Some((comments[1].clone(), None)), None),
         ),
-        (
-            tess.clone(),
-            (posts[1].clone(), None, Some(followings[0].clone())),
-        ),
+        (tess.clone(), (posts[1].clone(), None, Some(followings[0]))),
     ];
     assert_eq!(Ok(expected), data);
 
@@ -682,7 +674,7 @@ fn selecting_crazy_nested_joins() {
             sean.clone(),
             (
                 posts[0].clone(),
-                Some((comments[0].clone(), Some(likes[0].clone()))),
+                Some((comments[0].clone(), Some(likes[0]))),
             ),
             Some(followings[0]),
         ),
@@ -692,16 +684,16 @@ fn selecting_crazy_nested_joins() {
             Some(followings[0]),
         ),
         (
-            sean.clone(),
+            sean,
             (posts[2].clone(), Some((comments[1].clone(), None))),
             Some(followings[0]),
         ),
-        (tess.clone(), (posts[1].clone(), None), None),
+        (tess, (posts[1].clone(), None), None),
     ];
     assert_eq!(Ok(expected), data);
 }
 
-fn connection_with_fixture_data_for_multitable_joins() -> (TestConnection, TestData) {
+pub(crate) fn connection_with_fixture_data_for_multitable_joins() -> (TestConnection, TestData) {
     let mut connection = connection_with_sean_and_tess_in_users_table();
 
     let sean = find_user_by_name("Sean", &mut connection);
@@ -775,11 +767,11 @@ fn connection_with_fixture_data_for_multitable_joins() -> (TestConnection, TestD
     (connection, test_data)
 }
 
-struct TestData {
-    sean: User,
-    tess: User,
-    posts: Vec<Post>,
-    comments: Vec<Comment>,
-    likes: Vec<Like>,
-    followings: Vec<Following>,
+pub struct TestData {
+    pub sean: User,
+    pub tess: User,
+    pub posts: Vec<Post>,
+    pub comments: Vec<Comment>,
+    pub likes: Vec<Like>,
+    pub followings: Vec<Following>,
 }
diff --git a/diesel_tests/tests/schema/backend_specifics.rs b/diesel_tests/tests/schema/backend_specifics.rs
index 91055d246fae..4ef331bc25a7 100644
--- a/diesel_tests/tests/schema/backend_specifics.rs
+++ b/diesel_tests/tests/schema/backend_specifics.rs
@@ -1,6 +1,8 @@
 use super::*;
 
-#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName)]
+#[derive(
+    PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName, Selectable,
+)]
 #[diesel(belongs_to(User))]
 #[diesel(table_name = posts)]
 pub struct Post {
@@ -13,8 +15,8 @@ pub struct Post {
 impl Post {
     pub fn new(id: i32, user_id: i32, title: &str, body: Option<&str>) -> Self {
         Post {
-            id: id,
-            user_id: user_id,
+            id,
+            user_id,
             title: title.to_string(),
             body: body.map(|s| s.to_string()),
         }
diff --git a/diesel_tests/tests/schema/mod.rs b/diesel_tests/tests/schema/mod.rs
index 954f71e565ce..2c0d2068accf 100644
--- a/diesel_tests/tests/schema/mod.rs
+++ b/diesel_tests/tests/schema/mod.rs
@@ -32,7 +32,7 @@ pub struct User {
 impl User {
     pub fn new(id: i32, name: &str) -> Self {
         User {
-            id: id,
+            id,
             name: name.to_string(),
             hair_color: None,
         }
@@ -40,7 +40,7 @@ impl User {
 
     pub fn with_hair_color(id: i32, name: &str, hair_color: &str) -> Self {
         User {
-            id: id,
+            id,
             name: name.to_string(),
             hair_color: Some(hair_color.to_string()),
         }
@@ -61,8 +61,8 @@ impl UserName {
     }
 }
 
-#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
-#[diesel(belongs_to(Post))]
+#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, Selectable)]
+#[diesel(belongs_to(Post), table_name = comments)]
 pub struct Comment {
     id: i32,
     post_id: i32,
@@ -72,14 +72,16 @@ pub struct Comment {
 impl Comment {
     pub fn new(id: i32, post_id: i32, text: &str) -> Self {
         Comment {
-            id: id,
-            post_id: post_id,
+            id,
+            post_id,
             text: text.into(),
         }
     }
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Associations, Identifiable)]
+#[derive(
+    Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Associations, Identifiable, Selectable,
+)]
 #[diesel(belongs_to(User))]
 #[diesel(belongs_to(Post))]
 #[diesel(table_name = followings)]
@@ -140,7 +142,7 @@ pub struct NewPost {
 impl NewPost {
     pub fn new(user_id: i32, title: &str, body: Option<&str>) -> Self {
         NewPost {
-            user_id: user_id,
+            user_id,
             title: title.into(),
             body: body.map(|b| b.into()),
         }
@@ -163,10 +165,7 @@ pub struct FkTest {
 
 impl FkTest {
     pub fn new(id: i32, fk_id: i32) -> Self {
-        FkTest {
-            id: id,
-            fk_id: fk_id,
-        }
+        FkTest { id, fk_id }
     }
 }
 
@@ -177,14 +176,16 @@ pub struct NullableColumn {
     value: Option<i32>,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Identifiable, Associations)]
+#[derive(
+    Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Identifiable, Associations, Selectable,
+)]
 #[diesel(table_name = likes)]
-#[diesel(primary_key(user_id, comment_id))]
+#[diesel(primary_key(comment_id, user_id))]
 #[diesel(belongs_to(User))]
 #[diesel(belongs_to(Comment))]
 pub struct Like {
-    pub user_id: i32,
     pub comment_id: i32,
+    pub user_id: i32,
 }
 
 #[cfg(feature = "postgres")]
diff --git a/diesel_tests/tests/schema/postgres_specific_schema.rs b/diesel_tests/tests/schema/postgres_specific_schema.rs
index d1a48bc0651f..cbf812a949ff 100644
--- a/diesel_tests/tests/schema/postgres_specific_schema.rs
+++ b/diesel_tests/tests/schema/postgres_specific_schema.rs
@@ -1,6 +1,8 @@
 use super::{posts, User};
 
-#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName)]
+#[derive(
+    PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName, Selectable,
+)]
 #[diesel(table_name = posts)]
 #[diesel(belongs_to(User))]
 pub struct Post {
@@ -14,8 +16,8 @@ pub struct Post {
 impl Post {
     pub fn new(id: i32, user_id: i32, title: &str, body: Option<&str>) -> Self {
         Post {
-            id: id,
-            user_id: user_id,
+            id,
+            user_id,
             title: title.to_string(),
             body: body.map(|s| s.to_string()),
             tags: Vec::new(),
diff --git a/diesel_tests/tests/schema_dsl/structures.rs b/diesel_tests/tests/schema_dsl/structures.rs
index ddd8b2e8bf55..2a629508373a 100644
--- a/diesel_tests/tests/schema_dsl/structures.rs
+++ b/diesel_tests/tests/schema_dsl/structures.rs
@@ -8,10 +8,7 @@ pub struct CreateTable<'a, Cols> {
 
 impl<'a, Cols> CreateTable<'a, Cols> {
     pub fn new(name: &'a str, columns: Cols) -> Self {
-        CreateTable {
-            name: name,
-            columns: columns,
-        }
+        CreateTable { name, columns }
     }
 }
 
@@ -26,8 +23,8 @@ pub struct Column<'a, T> {
 impl<'a, T> Column<'a, T> {
     pub fn new(name: &'a str, type_name: &'a str) -> Self {
         Column {
-            name: name,
-            type_name: type_name,
+            name,
+            type_name,
             _marker: PhantomData,
         }
     }
diff --git a/diesel_tests/tests/schema_inference.rs b/diesel_tests/tests/schema_inference.rs
index 151ccd6eca02..37d255dadf9d 100644
--- a/diesel_tests/tests/schema_inference.rs
+++ b/diesel_tests/tests/schema_inference.rs
@@ -171,7 +171,7 @@ mod sqlite {
 
         let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11);
         let inferred_datetime_types = InferredDatetimeTypes {
-            dt: dt,
+            dt,
             date: dt.date(),
             time: dt.time(),
             timestamp: dt,
diff --git a/diesel_tests/tests/select.rs b/diesel_tests/tests/select.rs
index eced99460a69..ad0e3683fac1 100644
--- a/diesel_tests/tests/select.rs
+++ b/diesel_tests/tests/select.rs
@@ -64,7 +64,7 @@ fn with_select_sql() {
         .execute(connection)
         .unwrap();
 
-    assert_eq!(Ok(3), select_count.clone().first(connection));
+    assert_eq!(Ok(3), select_count.first(connection));
 }
 
 #[test]
diff --git a/diesel_tests/tests/select_by.rs b/diesel_tests/tests/select_by.rs
index 91daad4137e0..ce5886474507 100644
--- a/diesel_tests/tests/select_by.rs
+++ b/diesel_tests/tests/select_by.rs
@@ -217,3 +217,512 @@ fn mixed_selectable_and_plain_select() {
         .unwrap();
     assert_eq!(expected_data, actual_data);
 }
+
+// The following tests are duplicates from tests in joins.rs
+// They are used to verify that selectable behaves equivalent to the corresponding
+// raw select
+#[test]
+fn selecting_parent_child_grandchild() {
+    use crate::joins::TestData;
+
+    let (mut connection, test_data) =
+        crate::joins::connection_with_fixture_data_for_multitable_joins();
+    let TestData {
+        sean,
+        tess,
+        posts,
+        comments,
+        ..
+    } = test_data;
+
+    let data = users::table
+        .inner_join(posts::table.inner_join(comments::table))
+        .order((users::id, posts::id, comments::id))
+        .select(<(User, (Post, Comment)) as SelectableHelper<_>>::as_select())
+        .load(&mut connection);
+    let expected = vec![
+        (sean.clone(), (posts[0].clone(), comments[0].clone())),
+        (sean.clone(), (posts[0].clone(), comments[2].clone())),
+        (sean.clone(), (posts[2].clone(), comments[1].clone())),
+    ];
+    assert_eq!(Ok(expected), data);
+
+    let data = users::table
+        .inner_join(
+            posts::table
+                .on(users::id.eq(posts::user_id).and(posts::id.eq(posts[0].id)))
+                .inner_join(comments::table),
+        )
+        .order((users::id, posts::id, comments::id))
+        .select(<(User, (Post, Comment)) as SelectableHelper<_>>::as_select())
+        .load(&mut connection);
+    let expected = vec![
+        (sean.clone(), (posts[0].clone(), comments[0].clone())),
+        (sean.clone(), (posts[0].clone(), comments[2].clone())),
+    ];
+    assert_eq!(Ok(expected), data);
+
+    let data = users::table
+        .inner_join(posts::table.left_outer_join(comments::table))
+        .order((users::id, posts::id, comments::id))
+        .select(<(User, (Post, Option<Comment>)) as SelectableHelper<_>>::as_select())
+        .load(&mut connection);
+    let expected = vec![
+        (sean.clone(), (posts[0].clone(), Some(comments[0].clone()))),
+        (sean.clone(), (posts[0].clone(), Some(comments[2].clone()))),
+        (sean.clone(), (posts[2].clone(), Some(comments[1].clone()))),
+        (tess.clone(), (posts[1].clone(), None)),
+    ];
+    assert_eq!(Ok(expected), data);
+
+    let data = users::table
+        .left_outer_join(posts::table.left_outer_join(comments::table))
+        .order((users::id, posts::id, comments::id))
+        .select(<(User, Option<(Post, Option<Comment>)>) as SelectableHelper<_>>::as_select())
+        .load(&mut connection);
+    let expected = vec![
+        (
+            sean.clone(),
+            Some((posts[0].clone(), Some(comments[0].clone()))),
+        ),
+        (
+            sean.clone(),
+            Some((posts[0].clone(), Some(comments[2].clone()))),
+        ),
+        (
+            sean.clone(),
+            Some((posts[2].clone(), Some(comments[1].clone()))),
+        ),
+        (tess.clone(), Some((posts[1].clone(), None))),
+    ];
+    assert_eq!(Ok(expected), data);
+
+    let data = users::table
+        .left_outer_join(posts::table.inner_join(comments::table))
+        .order((users::id, posts::id, comments::id))
+        .select(<(User, Option<(Post, Comment)>) as SelectableHelper<_>>::as_select())
+        .load(&mut connection);
+    let expected = vec![
+        (sean.clone(), Some((posts[0].clone(), comments[0].clone()))),
+        (sean.clone(), Some((posts[0].clone(), comments[2].clone()))),
+        (sean, Some((posts[2].clone(), comments[1].clone()))),
+        (tess, None),
+    ];
+    assert_eq!(Ok(expected), data);
+}
+
+#[test]
+fn selecting_parent_child_grandchild_nested() {
+    use crate::joins::TestData;
+
+    let (mut connection, test_data) =
+        crate::joins::connection_with_fixture_data_for_multitable_joins();
+    let TestData {
+        sean,
+        tess,
+        posts,
+        comments,
+        ..
+    } = test_data;
+
+    #[derive(Queryable, Selectable, Clone, Debug, PartialEq)]
+    #[diesel(table_name = users)]
+    struct User1 {
+        id: i32,
+        name: String,
+        hair_color: Option<String>,
+        #[diesel(embed)]
+        post: Post1,
+    }
+
+    #[derive(Queryable, Selectable, Clone, Debug, PartialEq)]
+    #[diesel(table_name = posts)]
+    struct Post1 {
+        id: i32,
+        user_id: i32,
+        title: String,
+        body: Option<String>,
+        #[diesel(embed)]
+        comment: Comment,
+    }
+
+    let data = users::table
+        .inner_join(posts::table.inner_join(comments::table))
+        .order((users::id, posts::id, comments::id))
+        .select(User1::as_select())
+        .load(&mut connection);
+    let expected = vec![
+        User1 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color.clone(),
+            post: Post1 {
+                id: posts[0].id,
+                user_id: posts[0].user_id,
+                title: posts[0].title.clone(),
+                body: posts[0].body.clone(),
+                comment: comments[0].clone(),
+            },
+        },
+        User1 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color.clone(),
+            post: Post1 {
+                id: posts[0].id,
+                user_id: posts[0].user_id,
+                title: posts[0].title.clone(),
+                body: posts[0].body.clone(),
+                comment: comments[2].clone(),
+            },
+        },
+        User1 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color.clone(),
+            post: Post1 {
+                id: posts[2].id,
+                user_id: posts[2].user_id,
+                title: posts[2].title.clone(),
+                body: posts[2].body.clone(),
+                comment: comments[1].clone(),
+            },
+        },
+    ];
+    assert_eq!(Ok(expected), data);
+
+    #[derive(Queryable, Selectable, Clone, Debug, PartialEq)]
+    #[diesel(table_name = users)]
+    struct User2 {
+        id: i32,
+        name: String,
+        hair_color: Option<String>,
+        #[diesel(embed)]
+        post: Post2,
+    }
+
+    #[derive(Queryable, Selectable, Clone, Debug, PartialEq)]
+    #[diesel(table_name = posts)]
+    struct Post2 {
+        id: i32,
+        user_id: i32,
+        title: String,
+        body: Option<String>,
+        #[diesel(embed)]
+        comment: Option<Comment>,
+    }
+
+    let data = users::table
+        .inner_join(posts::table.left_outer_join(comments::table))
+        .order((users::id, posts::id, comments::id))
+        .select(User2::as_select())
+        .load(&mut connection);
+    let expected = vec![
+        User2 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color.clone(),
+            post: Post2 {
+                id: posts[0].id,
+                user_id: posts[0].user_id,
+                title: posts[0].title.clone(),
+                body: posts[0].body.clone(),
+                comment: Some(comments[0].clone()),
+            },
+        },
+        User2 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color.clone(),
+            post: Post2 {
+                id: posts[0].id,
+                user_id: posts[0].user_id,
+                title: posts[0].title.clone(),
+                body: posts[0].body.clone(),
+                comment: Some(comments[2].clone()),
+            },
+        },
+        User2 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color.clone(),
+            post: Post2 {
+                id: posts[2].id,
+                user_id: posts[2].user_id,
+                title: posts[2].title.clone(),
+                body: posts[2].body.clone(),
+                comment: Some(comments[1].clone()),
+            },
+        },
+        User2 {
+            id: tess.id,
+            name: tess.name.clone(),
+            hair_color: tess.hair_color.clone(),
+            post: Post2 {
+                id: posts[1].id,
+                user_id: posts[1].user_id,
+                title: posts[1].title.clone(),
+                body: posts[1].body.clone(),
+                comment: None,
+            },
+        },
+    ];
+    assert_eq!(Ok(expected), data);
+
+    #[derive(Queryable, Selectable, Clone, Debug, PartialEq)]
+    #[diesel(table_name = users)]
+    struct User3 {
+        id: i32,
+        name: String,
+        hair_color: Option<String>,
+        #[diesel(embed)]
+        post: Option<Post3>,
+    }
+
+    #[derive(Queryable, Selectable, Clone, Debug, PartialEq)]
+    #[diesel(table_name = posts)]
+    struct Post3 {
+        id: i32,
+        user_id: i32,
+        title: String,
+        body: Option<String>,
+        #[diesel(embed)]
+        comment: Option<Comment>,
+    }
+
+    let data = users::table
+        .left_outer_join(posts::table.left_outer_join(comments::table))
+        .order((users::id, posts::id, comments::id))
+        .select(User3::as_select())
+        .load(&mut connection);
+    let expected = vec![
+        User3 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color.clone(),
+            post: Some(Post3 {
+                id: posts[0].id,
+                user_id: posts[0].user_id,
+                title: posts[0].title.clone(),
+                body: posts[0].body.clone(),
+                comment: Some(comments[0].clone()),
+            }),
+        },
+        User3 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color.clone(),
+            post: Some(Post3 {
+                id: posts[0].id,
+                user_id: posts[0].user_id,
+                title: posts[0].title.clone(),
+                body: posts[0].body.clone(),
+                comment: Some(comments[2].clone()),
+            }),
+        },
+        User3 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color.clone(),
+            post: Some(Post3 {
+                id: posts[2].id,
+                user_id: posts[2].user_id,
+                title: posts[2].title.clone(),
+                body: posts[2].body.clone(),
+                comment: Some(comments[1].clone()),
+            }),
+        },
+        User3 {
+            id: tess.id,
+            name: tess.name.clone(),
+            hair_color: tess.hair_color.clone(),
+            post: Some(Post3 {
+                id: posts[1].id,
+                user_id: posts[1].user_id,
+                title: posts[1].title.clone(),
+                body: posts[1].body.clone(),
+                comment: None,
+            }),
+        },
+    ];
+    assert_eq!(Ok(expected), data);
+
+    #[derive(Queryable, Selectable, Clone, Debug, PartialEq)]
+    #[diesel(table_name = users)]
+    struct User4 {
+        id: i32,
+        name: String,
+        hair_color: Option<String>,
+        #[diesel(embed)]
+        post: Option<Post4>,
+    }
+
+    #[derive(Queryable, Selectable, Clone, Debug, PartialEq)]
+    #[diesel(table_name = posts)]
+    struct Post4 {
+        id: i32,
+        user_id: i32,
+        title: String,
+        body: Option<String>,
+        #[diesel(embed)]
+        comment: Comment,
+    }
+
+    let data = users::table
+        .left_outer_join(posts::table.inner_join(comments::table))
+        .order((users::id, posts::id, comments::id))
+        .select(User4::as_select())
+        .load(&mut connection);
+    let expected = vec![
+        User4 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color.clone(),
+            post: Some(Post4 {
+                id: posts[0].id,
+                user_id: posts[0].user_id,
+                title: posts[0].title.clone(),
+                body: posts[0].body.clone(),
+                comment: comments[0].clone(),
+            }),
+        },
+        User4 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color.clone(),
+            post: Some(Post4 {
+                id: posts[0].id,
+                user_id: posts[0].user_id,
+                title: posts[0].title.clone(),
+                body: posts[0].body.clone(),
+                comment: comments[2].clone(),
+            }),
+        },
+        User4 {
+            id: sean.id,
+            name: sean.name.clone(),
+            hair_color: sean.hair_color,
+            post: Some(Post4 {
+                id: posts[2].id,
+                user_id: posts[2].user_id,
+                title: posts[2].title.clone(),
+                body: posts[2].body.clone(),
+                comment: comments[1].clone(),
+            }),
+        },
+        User4 {
+            id: tess.id,
+            name: tess.name.clone(),
+            hair_color: tess.hair_color,
+            post: None,
+        },
+    ];
+    assert_eq!(Ok(expected), data);
+}
+
+#[test]
+fn selecting_grandchild_child_parent() {
+    use crate::joins::TestData;
+    let (mut connection, test_data) =
+        crate::joins::connection_with_fixture_data_for_multitable_joins();
+    let TestData {
+        sean,
+        posts,
+        comments,
+        ..
+    } = test_data;
+
+    let data = comments::table
+        .inner_join(posts::table.inner_join(users::table))
+        .order((users::id, posts::id, comments::id))
+        .select(<(Comment, (Post, User)) as SelectableHelper<_>>::as_select())
+        .load(&mut connection);
+    let expected = vec![
+        (comments[0].clone(), (posts[0].clone(), sean.clone())),
+        (comments[2].clone(), (posts[0].clone(), sean.clone())),
+        (comments[1].clone(), (posts[2].clone(), sean)),
+    ];
+    assert_eq!(Ok(expected), data);
+}
+
+#[test]
+fn selecting_crazy_nested_joins() {
+    use crate::joins::TestData;
+    let (mut connection, test_data) =
+        crate::joins::connection_with_fixture_data_for_multitable_joins();
+    let TestData {
+        sean,
+        tess,
+        posts,
+        likes,
+        comments,
+        followings,
+        ..
+    } = test_data;
+
+    let data = users::table
+        .inner_join(
+            posts::table
+                .left_join(comments::table.left_join(likes::table))
+                .left_join(followings::table),
+        )
+        .select(<(
+            User,
+            (Post, Option<(Comment, Option<Like>)>, Option<Following>),
+        ) as SelectableHelper<_>>::as_select())
+        .order((users::id, posts::id, comments::id))
+        .load(&mut connection);
+    let expected = vec![
+        (
+            sean.clone(),
+            (
+                posts[0].clone(),
+                Some((comments[0].clone(), Some(likes[0]))),
+                None,
+            ),
+        ),
+        (
+            sean.clone(),
+            (posts[0].clone(), Some((comments[2].clone(), None)), None),
+        ),
+        (
+            sean.clone(),
+            (posts[2].clone(), Some((comments[1].clone(), None)), None),
+        ),
+        (tess.clone(), (posts[1].clone(), None, Some(followings[0]))),
+    ];
+    assert_eq!(Ok(expected), data);
+
+    let data = users::table
+        .inner_join(posts::table.left_join(comments::table.left_join(likes::table)))
+        .left_join(followings::table)
+        .order((users::id, posts::id, comments::id))
+        .select(<(
+            User,
+            (Post, Option<(Comment, Option<Like>)>),
+            Option<Following>,
+        ) as SelectableHelper<_>>::as_select())
+        .load(&mut connection);
+    let expected = vec![
+        (
+            sean.clone(),
+            (
+                posts[0].clone(),
+                Some((comments[0].clone(), Some(likes[0]))),
+            ),
+            Some(followings[0]),
+        ),
+        (
+            sean.clone(),
+            (posts[0].clone(), Some((comments[2].clone(), None))),
+            Some(followings[0]),
+        ),
+        (
+            sean,
+            (posts[2].clone(), Some((comments[1].clone(), None))),
+            Some(followings[0]),
+        ),
+        (tess, (posts[1].clone(), None), None),
+    ];
+    assert_eq!(Ok(expected), data);
+}
diff --git a/diesel_tests/tests/transactions.rs b/diesel_tests/tests/transactions.rs
index 11330b92cc93..7f273b4c2c3a 100644
--- a/diesel_tests/tests/transactions.rs
+++ b/diesel_tests/tests/transactions.rs
@@ -5,7 +5,7 @@ use diesel::*;
 #[test]
 #[cfg(not(feature = "sqlite"))] // FIXME: This test is only valid when operating on a file and not :memory:
 fn transaction_executes_fn_in_a_sql_transaction() {
-    const TEST_NAME: &'static str = "transaction_executes_fn_in_a_sql_transaction";
+    const TEST_NAME: &str = "transaction_executes_fn_in_a_sql_transaction";
     let conn1 = &mut connection_without_transaction();
     let conn2 = &mut connection_without_transaction();
     setup_test_table(conn1, TEST_NAME);
@@ -57,7 +57,7 @@ fn transaction_is_rolled_back_when_returned_an_error() {
 }
 
 // This test uses a SQLite3 fact to generate a rollback error,
-// so that we can verify `Error::RollbackError`. Reference:
+// so that we can verify error. Reference:
 // https://www.sqlite.org/lang_transaction.html
 //
 // The same trick cannot be used for PostgreSQL as it generates
@@ -87,9 +87,9 @@ fn transaction_rollback_returns_error() {
         Err(Error::NotFound)
     });
 
-    // Verify that the transaction failed with `RollbackError`.
-    assert!(r.is_err());
-    assert!(matches!(r.unwrap_err(), Error::RollbackError(_)));
+    // Verify that the transaction failed with an error from database (and not the original
+    // "NotFound").
+    assert!(matches!(r.unwrap_err(), Error::DatabaseError(_, _)));
 
     assert_eq!(0, count_test_table(connection, test_name));
     drop_test_table(connection, test_name);
@@ -98,7 +98,7 @@ fn transaction_rollback_returns_error() {
 #[test]
 fn transactions_can_be_nested() {
     let connection = &mut connection_without_transaction();
-    const TEST_NAME: &'static str = "transactions_can_be_nested";
+    const TEST_NAME: &str = "transactions_can_be_nested";
     setup_test_table(connection, TEST_NAME);
     fn get_count(connection: &mut TestConnection) -> i64 {
         count_test_table(connection, TEST_NAME)
diff --git a/diesel_tests/tests/types.rs b/diesel_tests/tests/types.rs
index 01250036d61c..669fdb6378fd 100644
--- a/diesel_tests/tests/types.rs
+++ b/diesel_tests/tests/types.rs
@@ -381,6 +381,7 @@ use std::{f32, f64};
 
 #[test]
 #[cfg(feature = "postgres")]
+#[allow(clippy::float_cmp)]
 fn f32_from_sql() {
     assert_eq!(0.0, query_single_value::<Float, f32>("0.0::real"));
     assert_eq!(0.5, query_single_value::<Float, f32>("0.5::real"));
@@ -398,6 +399,7 @@ fn f32_from_sql() {
 
 #[test]
 #[cfg(any(feature = "mysql", feature = "sqlite"))]
+#[allow(clippy::float_cmp)]
 fn f32_from_sql() {
     assert_eq!(0.0, query_single_value::<Float, f32>("0.0"));
     assert_eq!(0.5, query_single_value::<Float, f32>("0.5"));
@@ -412,6 +414,7 @@ fn f32_from_sql() {
 
 #[test]
 #[cfg(feature = "postgres")]
+#[allow(clippy::float_cmp)]
 fn f32_to_sql() {
     assert!(query_to_sql_equality::<Float, f32>("0.0::real", 0.0));
     assert!(query_to_sql_equality::<Float, f32>("0.5::real", 0.5));
@@ -458,6 +461,7 @@ fn f32_to_sql() {
 
 #[test]
 #[cfg(feature = "postgres")]
+#[allow(clippy::float_cmp)]
 fn f64_from_sql() {
     assert_eq!(
         0.0,
@@ -481,6 +485,7 @@ fn f64_from_sql() {
 
 #[test]
 #[cfg(any(feature = "mysql", feature = "sqlite"))]
+#[allow(clippy::float_cmp)]
 fn f64_from_sql() {
     assert_eq!(0.0, query_single_value::<Double, f64>("0.0"));
     assert_eq!(0.5, query_single_value::<Double, f64>("0.5"));
@@ -1077,6 +1082,26 @@ fn pg_v4address_from_sql() {
         query_single_value::<Inet, ipnetwork::IpNetwork>(query)
     );
 }
+
+#[test]
+#[cfg(feature = "postgres")]
+fn pg_v4address_from_sql_ipnet() {
+    use std::str::FromStr;
+
+    let query = "'192.168.1.0/24'::cidr";
+    let expected_value = ipnet::IpNet::V4(ipnet::Ipv4Net::from_str("192.168.1.0/24").unwrap());
+    assert_eq!(
+        expected_value,
+        query_single_value::<Cidr, ipnet::IpNet>(query)
+    );
+    let query = "'192.168.1.0/24'::inet";
+    let expected_value = ipnet::IpNet::V4(ipnet::Ipv4Net::from_str("192.168.1.0/24").unwrap());
+    assert_eq!(
+        expected_value,
+        query_single_value::<Inet, ipnet::IpNet>(query)
+    );
+}
+
 #[test]
 #[cfg(feature = "postgres")]
 fn pg_v6address_from_sql() {
@@ -1099,6 +1124,24 @@ fn pg_v6address_from_sql() {
     );
 }
 
+#[test]
+#[cfg(feature = "postgres")]
+fn pg_v6address_from_sql_ipnet() {
+    use std::str::FromStr;
+
+    let query = "'2001:4f8:3:ba::/64'::cidr";
+    let expected_value = ipnet::IpNet::V6(ipnet::Ipv6Net::from_str("2001:4f8:3:ba::/64").unwrap());
+    assert_eq!(
+        expected_value,
+        query_single_value::<Cidr, ipnet::IpNet>(query)
+    );
+    let query = "'2001:4f8:3:ba::/64'::inet";
+    let expected_value = ipnet::IpNet::V6(ipnet::Ipv6Net::from_str("2001:4f8:3:ba::/64").unwrap());
+    assert_eq!(
+        expected_value,
+        query_single_value::<Inet, ipnet::IpNet>(query)
+    );
+}
 #[test]
 #[cfg(feature = "postgres")]
 fn pg_v4address_to_sql_v4address() {
@@ -1126,6 +1169,30 @@ fn pg_v4address_to_sql_v4address() {
     ));
 }
 
+#[test]
+#[cfg(feature = "postgres")]
+fn pg_v4address_to_sql_v4address_ipnet() {
+    use std::str::FromStr;
+
+    let expected_value = "'192.168.1'::cidr";
+    let value = ipnet::IpNet::V4(ipnet::Ipv4Net::from_str("192.168.1.0/24").unwrap());
+    assert!(query_to_sql_equality::<Cidr, ipnet::IpNet>(
+        expected_value,
+        value
+    ));
+    let expected_value = "'192.168.1.0/24'::inet";
+    let value = ipnet::IpNet::V4(ipnet::Ipv4Net::from_str("192.168.1.0/24").unwrap());
+    assert!(query_to_sql_equality::<Inet, ipnet::IpNet>(
+        expected_value,
+        value
+    ));
+    let expected_non_equal_value = "'192.168.1.0/23'::inet";
+    assert!(!query_to_sql_equality::<Inet, ipnet::IpNet>(
+        expected_non_equal_value,
+        value
+    ));
+}
+
 #[test]
 #[cfg(feature = "postgres")]
 fn pg_v6address_to_sql_v6address() {
@@ -1153,6 +1220,30 @@ fn pg_v6address_to_sql_v6address() {
     ));
 }
 
+#[test]
+#[cfg(feature = "postgres")]
+fn pg_v6address_to_sql_v6address_ipnet() {
+    use std::str::FromStr;
+
+    let expected_value = "'2001:4f8:3:ba::/64'::cidr";
+    let value = ipnet::IpNet::V6(ipnet::Ipv6Net::from_str("2001:4f8:3:ba::/64").unwrap());
+    assert!(query_to_sql_equality::<Cidr, ipnet::IpNet>(
+        expected_value,
+        value
+    ));
+    let expected_value = "'2001:4f8:3:ba::/64'::cidr";
+    let value = ipnet::IpNet::V6(ipnet::Ipv6Net::from_str("2001:4f8:3:ba::/64").unwrap());
+    assert!(query_to_sql_equality::<Inet, ipnet::IpNet>(
+        expected_value,
+        value
+    ));
+    let expected_non_equal_value = "'2001:4f8:3:ba::/63'::cidr";
+    assert!(!query_to_sql_equality::<Inet, ipnet::IpNet>(
+        expected_non_equal_value,
+        value
+    ));
+}
+
 #[test]
 #[cfg(feature = "postgres")]
 fn pg_json_from_sql() {
diff --git a/diesel_tests/tests/types_roundtrip.rs b/diesel_tests/tests/types_roundtrip.rs
index bc752aaa9467..ca2c237609f2 100644
--- a/diesel_tests/tests/types_roundtrip.rs
+++ b/diesel_tests/tests/types_roundtrip.rs
@@ -69,6 +69,7 @@ macro_rules! test_round_trip {
     };
     ($test_name:ident, $sql_type:ty, $tpe:ty, $map_fn:ident, $cmp: expr) => {
         #[test]
+        #[allow(clippy::type_complexity)]
         fn $test_name() {
             use diesel::sql_types::*;
 
@@ -91,6 +92,7 @@ macro_rules! test_round_trip {
     };
 }
 
+#[allow(clippy::float_cmp)]
 pub fn f32_ne(a: &f32, b: &f32) -> bool {
     if a.is_nan() && b.is_nan() {
         false
@@ -99,6 +101,7 @@ pub fn f32_ne(a: &f32, b: &f32) -> bool {
     }
 }
 
+#[allow(clippy::float_cmp)]
 pub fn f64_ne(a: &f64, b: &f64) -> bool {
     if a.is_nan() && b.is_nan() {
         false
@@ -184,19 +187,43 @@ mod pg_types {
         mk_macaddr
     );
     test_round_trip!(cidr_v4_roundtrips, Cidr, (u8, u8, u8, u8), mk_ipv4);
+    test_round_trip!(
+        cidr_v4_roundtrips_ipnet,
+        Cidr,
+        (u8, u8, u8, u8),
+        mk_ipv4_ipnet
+    );
     test_round_trip!(
         cidr_v6_roundtrips,
         Cidr,
         (u16, u16, u16, u16, u16, u16, u16, u16),
         mk_ipv6
     );
+    test_round_trip!(
+        cidr_v6_roundtrips_ipnet,
+        Cidr,
+        (u16, u16, u16, u16, u16, u16, u16, u16),
+        mk_ipv6_ipnet
+    );
     test_round_trip!(inet_v4_roundtrips, Inet, (u8, u8, u8, u8), mk_ipv4);
+    test_round_trip!(
+        inet_v4_roundtrips_ipnet,
+        Inet,
+        (u8, u8, u8, u8),
+        mk_ipv4_ipnet
+    );
     test_round_trip!(
         inet_v6_roundtrips,
         Inet,
         (u16, u16, u16, u16, u16, u16, u16, u16),
         mk_ipv6
     );
+    test_round_trip!(
+        inet_v6_roundtrips_ipnet,
+        Inet,
+        (u16, u16, u16, u16, u16, u16, u16, u16),
+        mk_ipv6_ipnet
+    );
     test_round_trip!(bigdecimal_roundtrips, Numeric, (i64, u64), mk_bigdecimal);
     test_round_trip!(int4range_roundtrips, Range<Int4>, (i32, i32), mk_bounds);
     test_round_trip!(int8range_roundtrips, Range<Int8>, (i64, i64), mk_bounds);
@@ -228,10 +255,11 @@ mod pg_types {
     test_round_trip!(json_roundtrips, Json, SerdeWrapper, mk_serde_json);
     test_round_trip!(jsonb_roundtrips, Jsonb, SerdeWrapper, mk_serde_json);
 
+    #[allow(clippy::type_complexity)]
     fn mk_uuid(data: (u32, u16, u16, (u8, u8, u8, u8, u8, u8, u8, u8))) -> self::uuid::Uuid {
         let a = data.3;
         let b = [a.0, a.1, a.2, a.3, a.4, a.5, a.6, a.7];
-        uuid::Uuid::from_fields(data.0, data.1, data.2, &b).unwrap()
+        uuid::Uuid::from_fields(data.0, data.1, data.2, &b)
     }
 
     fn mk_macaddr(data: (u8, u8, u8, u8, u8, u8)) -> [u8; 6] {
@@ -244,6 +272,12 @@ mod pg_types {
         ipnetwork::IpNetwork::V4(ipnetwork::Ipv4Network::new(ip, 32).unwrap())
     }
 
+    fn mk_ipv4_ipnet(data: (u8, u8, u8, u8)) -> ipnet::IpNet {
+        use std::net::Ipv4Addr;
+        let ip = Ipv4Addr::new(data.0, data.1, data.2, data.3);
+        ipnet::IpNet::V4(ipnet::Ipv4Net::new(ip, 32).unwrap())
+    }
+
     fn mk_ipv6(data: (u16, u16, u16, u16, u16, u16, u16, u16)) -> ipnetwork::IpNetwork {
         use std::net::Ipv6Addr;
         let ip = Ipv6Addr::new(
@@ -252,6 +286,14 @@ mod pg_types {
         ipnetwork::IpNetwork::V6(ipnetwork::Ipv6Network::new(ip, 128).unwrap())
     }
 
+    fn mk_ipv6_ipnet(data: (u16, u16, u16, u16, u16, u16, u16, u16)) -> ipnet::IpNet {
+        use std::net::Ipv6Addr;
+        let ip = Ipv6Addr::new(
+            data.0, data.1, data.2, data.3, data.4, data.5, data.6, data.7,
+        );
+        ipnet::IpNet::V6(ipnet::Ipv6Net::new(ip, 128).unwrap())
+    }
+
     fn mk_bounds<T: Ord + PartialEq>(data: (T, T)) -> (Bound<T>, Bound<T>) {
         if data.0 == data.1 {
             // This is invalid but we don't have a way to say that to quickcheck
@@ -300,12 +342,7 @@ mod pg_types {
             if r < earliest_pg_date {
                 let diff = earliest_pg_date - r;
                 r = earliest_pg_date + diff;
-            }
-            /*else if r > latest_pg_date {
-                let diff = r - latest_pg_date;
-                r = earliest_pg_date + diff;
-            }*/
-            else {
+            } else {
                 break;
             }
         }
@@ -457,7 +494,7 @@ mod mysql_types {
     pub fn mk_naive_timestamp((mut seconds, nanos): (i64, u32)) -> NaiveDateTime {
         // https://dev.mysql.com/doc/refman/8.0/en/datetime.html
         let earliest_mysql_date = NaiveDate::from_ymd(1970, 1, 1).and_hms(0, 0, 1);
-        let latest_mysql_date = NaiveDate::from_ymd(2038, 1, 19).and_hms(03, 14, 7);
+        let latest_mysql_date = NaiveDate::from_ymd(2038, 1, 19).and_hms(3, 14, 7);
 
         if seconds != 0 {
             seconds = earliest_mysql_date.timestamp()
@@ -600,7 +637,7 @@ pub fn mk_naive_date(days: u32) -> NaiveDate {
 
 #[cfg(feature = "mysql")]
 pub fn mk_naive_date(days: u32) -> NaiveDate {
-    let earliest_mysql_date = NaiveDate::from_ymd(1000, 01, 01);
+    let earliest_mysql_date = NaiveDate::from_ymd(1000, 1, 1);
     let latest_mysql_date = NaiveDate::from_ymd(9999, 12, 31);
     let num_days_representable = latest_mysql_date
         .signed_duration_since(earliest_mysql_date)
diff --git a/diesel_tests/tests/update.rs b/diesel_tests/tests/update.rs
index 35c0aa3fede8..229ae6130c0d 100644
--- a/diesel_tests/tests/update.rs
+++ b/diesel_tests/tests/update.rs
@@ -206,7 +206,7 @@ fn sql_syntax_is_correct_when_option_field_comes_mixed_with_non_option() {
         .first::<Post>(connection)
         .unwrap();
 
-    let expected_post = Post::new(post.id, sean.id, "Hello".into(), Some("earth".into()));
+    let expected_post = Post::new(post.id, sean.id, "Hello", Some("earth"));
     assert_eq!(expected_post, post);
 }