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

Issue:
IS NOT DISTINCT FROM ANY is not a valid PostgreSQL query
## Setup

### Versions

- **Rust:** 1.51.0
- **Diesel:** master (7e676025)
- **Database:** PostgreSQL 13.1
- **Operating System:** Arch Linux

### Feature Flags

- **diesel:** postgres

## Problem Description

`IS NOT DISTINCT FROM ANY` is not a valid PostgresSQL statement, however Diesel allows compiling it and outputs an invalid Postgres query.


### Steps to reproduce
```rust
use diesel::{
    dsl::any,
    pg::PgQueryBuilder,
    query_builder::{QueryBuilder, QueryFragment},
    NullableExpressionMethods, PgExpressionMethods, QueryDsl,
};

fn main() {
    let mut backend = PgQueryBuilder::new();
    a::table
        .select(
            a::id
                .nullable()
                .is_not_distinct_from(any(b::table.select(b::id))),
        )
        .to_sql(&mut backend)
        .unwrap();
    println!("{}", backend.finish());
}

diesel::table! {
        a (id) {
                id -> Int4,
        }
}

diesel::table! {
        b (id) {
                id -> Nullable<Int4>,
        }
}

```

### What is the expected output?
Diesel should not allow this query to compile.
### What is the actual output?
Diesel compiles and outputs this query, which is not actually supported:
```sql
SELECT ("a"."id" IS NOT DISTINCT FROM ANY(SELECT "b"."id" FROM "b")) FROM "a"
```

## Checklist

- [x] I have already looked over the [issue tracker](https://github.com/diesel-rs/diesel/issues)  and the [disussion forum](https://github.com/diesel-rs/diesel/discussions)  for similar possible closed issues.
- [x] This issue can be reproduced on Rust's stable channel. (Your issue will be
  closed if this is not the case)
- [x] This issue can be reproduced without requiring a third party crate



Discussion / hints:
Thanks for opening this issue. I can reproduce this problem and would be happy to receive a fix for it. 
Looks like this is due to this:
https://github.com/diesel-rs/diesel/blob/7ff5e6327d5e88095cb4b342da13bf06d6d0d1cd/diesel/src/pg/expression/array_comparison.rs#L75-L81
which seems not really correct (looks like `Any<Expr>` is not really an expression by itself, and the current writing would allow it to also appear in a select).

It looks like one way to fix it would be to introduce something like:
```rust
trait AsExpressionOrArrayComparison<T> {
    type ExpressionOrArrayCmp: ExpressionOrArrayComparison<SqlType=T>;
    fn as_expression() -> Self::ExpressionOrArrayCmp;
}
impl<T, ST> AsExpressionOrArrayComparison<ST> for T: AsExpression<ST> { ... }
impl<Expr, ST> ExpressionOrArrayComparison for Any<Expr>
where
    Expr: Expression<SqlType = Array<ST>>,
    ST: SqlType + TypedExpressionType,
{
    type SqlType = ST;
}
```
and then use that instead of directly `AsExpression/Expression` in https://github.com/diesel-rs/diesel/blob/fed0da6a46baa2703872bc8bc788891913495ae1/diesel/src/expression_methods/global_expression_methods.rs#L24-L30

That would probably require updating https://github.com/diesel-rs/diesel/blob/0ec6a0ce762922eaa7264dcbd3b4707c4d1aebee/diesel/src/expression/helper_types.rs#L16 (or introduce a new similar one for `AsExpressionOrArrayComparison`).

I'm not sure to what extent we want to make the same changes for
```rust
impl<Expr, ST> Expression for All<Expr>
where
    Expr: Expression<SqlType = Array<ST>>,
    ST: SqlType + TypedExpressionType,
{
    type SqlType = ST;
}
```
as this seems to behave a bit differently: select works.
https://github.com/diesel-rs/diesel/blob/7ff5e6327d5e88095cb4b342da13bf06d6d0d1cd/diesel/src/pg/expression/array_comparison.rs#L129
Let me try to fix it.
> ```rust
> impl<T, ST> AsExpressionOrArrayComparison<ST> for T: AsExpression<ST> { ... }
> ```

I don't quite understand what this place means? Also how is ExpressionOrArrayComparison defined? Can you help me to explain it? Thanks!

@hi-rustin Every part in diesels query dsl ast currently implements `Expression`, which contains information about the type of the actual expression. The `Eq` operator is now simply a that takes two expressions of the same type as argument while the operator itself is an `Expression` of the type `Bool`. I think [this example](https://github.com/diesel-rs/diesel/blob/c0b613024adf970dc888453c984d42e86bad6b3e/diesel/src/expression/operators.rs#L189-L211) shows the basic idea quite good. 

On the other hand `Any` is currently also implemented as normal `Expression` that converts an `Expression` of the type  `Array<ST>` to the inner type `ST`. (See [here](https://github.com/diesel-rs/diesel/blob/c0b613024adf970dc888453c984d42e86bad6b3e/diesel/src/pg/expression/array_comparison.rs#L75-L81)). This does not really match the implementation in postgresql, as `any` is really some sort of custom thing that is only allowed in certain places.

We can fix that by doing the following steps:
1. Remove the the `Expression` impl for `any` (that one linked above).
2. We need to make sure that `something = ANY(…)` is valid after the first change. Now this does not work with the simplified `Eq` version presented above. We need to teach `Eq` to accept any `Expression` or the `any` operator as right site of the expression. For this we need to change the trait bounds [here](https://github.com/diesel-rs/diesel/blob/c0b613024adf970dc888453c984d42e86bad6b3e/diesel/src/expression_methods/global_expression_methods.rs#L28). A simple way to model the `Expression` or `any` condition as trait bound is to introduce two new traits:

```rust
trait AsExpressionOrArrayComparison<T> {
    type ExpressionOrArrayCmp: ExpressionOrArrayComparison<SqlType = T>;

    fn as_expression(self) -> Self::ExpressionOrArrayCmp;
}

trait ExpressionOrArrayComparison {
    type SqlType;
}
```

This mirrors the existing `AsExpression` and `Expression` trait. (`AsExpression` describes how to transform rust values into query ast nodes. It is implemented for all types implementing `Expression`  (as they are already query ast nodes) and for all types implementing `ToSql` (those generate bind parameters in the query ast)).

Now we provide 2 implementations for this trait:
* One for any type `T` that already implements `AsExpression<T>`:
```rust
impl<T, ST> AsExpressionOrArrayComparison<ST> for T 
where T: AsExpression<ST> 
{ 
    type ExpressionOrArrayCmp = T::Expression;

    fn as_expression(self) -> T::Expression {
        <T as AsExpression<ST>>::as_expression(self)
    }
 }

impl<T> ExpressionOrArrayComparison for T 
where T: Expression
{
    type SqlType = T::SqlType;
}
```
* One for the `any` type:
```rust
impl<Expr, ST> ExpressionOrArrayComparison for Any<Expr>
where
    Expr: Expression<SqlType = Array<ST>>,
    ST: SqlType + TypedExpressionType,
{
    type SqlType = ST
    
}

impl<Expr, ST> AsExpressionOrArrayComparison<ST> for Any<Expr>
where Self: ExpressionOrArrayComparison<SqlType = ST>
{
    type ExpressionOrArrayCmp = Self;

    fn as_expression(self) -> Self {
        self
    }
}
```

3. Now it we just need to change the definition of `ExpressionMethods::eq` [here](https://github.com/diesel-rs/diesel/blob/c0b613024adf970dc888453c984d42e86bad6b3e/diesel/src/expression_methods/global_expression_methods.rs#L28) to use the new `AsExpressionOrArrayComparison` instead of the existing `AsExpression` trait. This implies that also the [return type](https://github.com/diesel-rs/diesel/blob/c0b613024adf970dc888453c984d42e86bad6b3e/diesel/src/expression/helper_types.rs#L20) needs to be changed (Replace the `AsExpr` part there with the corresponding new version). Additional note: This also applies to a bunch of other operators. We should check the postgres manual here.



Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fbaf48684bc8..01b0494920a8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -175,7 +175,12 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
 * The `#[table_name]` attribute for derive macros can now refer to any path and is no
   longer limited to identifiers from the current scope.
 
-* Interacting with a database requires a mutable connection. 
+* Interacting with a database requires a mutable connection.
+
+* `eq_any()` now emits a `= ANY()` expression for the postgresql backend instead of `IN()`
+* `ne_all()` now emits a `!= ALL()` expression for the postgresql backend instead of `NOT IN()`
+* The sqlite backend now uses a single batch insert statement if there are now default values present 
+  in the values clause
 
 ### Fixed
 
@@ -230,6 +235,9 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
 
 * `diesel::pg::upsert` has been deprecated to support upsert queries on more than one backend.
   Please use `diesel::upsert` instead.
+  
+* `diesel::dsl::any` and `diesel::dsl::all` are now deprecated in 
+   favour of `ExpressionMethods::eq_any()` and `ExpressionMethods::ne_all()`
 
 ### Upgrade Notes
 
diff --git a/diesel/src/backend.rs b/diesel/src/backend.rs
index 7eef5bf366fa..8bdb52dd8682 100644
--- a/diesel/src/backend.rs
+++ b/diesel/src/backend.rs
@@ -20,7 +20,7 @@ use crate::sql_types::{self, HasSqlType};
 /// protocol used to communicated with the database.
 pub trait Backend
 where
-    Self: Sized,
+    Self: Sized + SqlDialect,
     Self: HasSqlType<sql_types::SmallInt>,
     Self: HasSqlType<sql_types::Integer>,
     Self: HasSqlType<sql_types::BigInt>,
@@ -73,19 +73,200 @@ pub trait BinaryRawValue<'a>: HasRawValue<'a> {
 /// `FromSql`. Equivalent to `<DB as Backend>::RawValue<'a>`.
 pub type RawValue<'a, DB> = <DB as HasRawValue<'a>>::RawValue;
 
-/// A trait indicating that implementing backend provides support for
-/// `RETURNING` clauses.
+/// This trait provides various options to configure the
+/// generated SQL for a specific backend.
 ///
-/// This trait has to be implemented in order to be able to use methods such as
-/// `get_results` and `returning`. Namely, any method which leads to usage of
-/// `RETURNING` clauses in SQL sent to backend will require that this trait
-/// be implemented for used backend.
-pub trait SupportsReturningClause {}
-/// Does this backend support 'ON CONFLICT' clause?
-pub trait SupportsOnConflictClause {}
-/// Does this backend support 'WHERE' clauses on 'ON CONFLICT' clauses?
-pub trait SupportsOnConflictTargetDecorations {}
-/// Does this backend support the bare `DEFAULT` keyword?
-pub trait SupportsDefaultKeyword {}
-/// Does this backend use the standard `SAVEPOINT` syntax?
-pub trait UsesAnsiSavepointSyntax {}
+/// Accessing anything from this trait is considered to be part of the
+/// public API. Implementing this trait is not considered to be part of
+/// diesels public API, as future versions of diesel may add additional
+/// associated constants here.
+///
+/// Each associated type is used to configure the behaviour
+/// of one or more [`QueryFragment`](crate::query_builder::QueryFragment)
+/// implementations by providing
+/// 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.
+pub trait SqlDialect {
+    /// Configures how this backends supports `RETURNING` clauses
+    ///
+    /// This allows backends to opt in  `RETURNING` clause support and to
+    /// provide a custom [`QueryFragment`](crate::query_builder::QueryFragment)
+    /// implementation for [`ReturningClause`](crate::query_builder::ReturningClause)
+    type ReturningClause;
+    /// Configures how this backend supports `ON CONFLICT` clauses
+    ///
+    /// This allows backends to opt in `ON CONFLICT` clause support
+    type OnConflictClause;
+    /// Configures how this backend handles the bare `DEFAULT` keyword for
+    /// inserting the default value in a `INSERT INTO` `VALUES` clause
+    ///
+    /// This allows backends to opt in support for `DEFAULT` value expressions
+    /// for insert statements
+    type InsertWithDefaultKeyword;
+    /// Configures how this backend handles Batch insert statements
+    ///
+    /// This allows backends to provide a custom [`QueryFragment`](crate::query_builder::QueryFragment)
+    /// implementation for [`BatchInsert`](crate::query_builder::BatchInsert)
+    type BatchInsertSupport;
+    /// Configures how this backend handles the `DEFAULT VALUES` clause for
+    /// insert statements.
+    ///
+    /// This allows backends to provide a custom [`QueryFragment`](crate::query_builder::QueryFragment)
+    /// implementation for [`DefaultValues`](crate::query_builder::DefaultValues)
+    type DefaultValueClauseForInsert;
+    /// Configures how this backend handles empty `FROM` clauses for select statements.
+    ///
+    /// This allows backends to provide a custom [`QueryFragment`](crate::query_builder::QueryFragment)
+    /// implementation for [`NoFromClause`](crate::query_builder::NoFromClause)
+    type EmptyFromClauseSyntax;
+    /// Configures how this backend handles `EXISTS()` expressions.
+    ///
+    /// This allows backends to provide a custom [`QueryFragment`](crate::query_builder::QueryFragment)
+    /// implementation for [`Exists`](crate::expression::exists::Exists)
+    type ExistsSyntax;
+
+    /// Configures how this backend handles `IN()` and `NOT IN()` expressions.
+    ///
+    /// This allows backends to provide custom [`QueryFragment`](crate::query_builder::QueryFragment)
+    /// implementations for [`In`](crate::expression::array_comparison::In),
+    /// [`NotIn`](crate::expression::array_comparison::NotIn) and
+    /// [`Many`](crate::expression::array_comparison::Many)
+    type ArrayComparision;
+}
+
+/// This module contains all options provided by diesel to configure the [`SqlDialect`] trait.
+pub mod sql_dialect {
+    #[cfg(doc)]
+    use super::SqlDialect;
+
+    /// This module contains all diesel provided reusable options to
+    /// configure [`SqlDialect::OnConflictClause`]
+    pub 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
+        /// implementing this trait opts into reusing diesels existing `ON CONFLICT`
+        /// `QueryFragment` implementations
+        pub trait SupportsOnConflictClause {}
+
+        /// This marker type indicates that `ON CONFLICT` clauses are not supported for this backend
+        #[derive(Debug, Copy, Clone)]
+        pub struct DoesNotSupportOnConflictClause;
+    }
+
+    /// This module contains all reusable options to configure
+    /// [`SqlDialect::ReturningClause`]
+    pub 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
+        /// implementing this trait opts in supporting `RETURNING` clause syntax
+        pub trait SupportsReturningClause {}
+
+        /// Indicates that a backend provides support for `RETURNING` clauses
+        /// using the postgresql `RETURNING` syntax
+        #[derive(Debug, Copy, Clone)]
+        pub struct PgLikeReturningClause;
+
+        /// Indicates that a backend does not support `RETURNING` clauses
+        #[derive(Debug, Copy, Clone)]
+        pub struct DoesNotSupportReturningClause;
+
+        impl SupportsReturningClause for PgLikeReturningClause {}
+    }
+
+    /// This module contains all reusable options to configure
+    /// [`SqlDialect::InsertWithDefaultKeyword`]
+    pub 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
+        ///
+        /// If you use a custom type to specify specialized support for `DEFAULT`
+        /// expressions implementing this trait opts in support for `DEFAULT`
+        /// value expressions for inserts. Otherwise diesel will emulate this
+        /// behaviour.
+        pub trait SupportsDefaultKeyword {}
+
+        /// Indicates that a backend support `DEFAULT` value expressions
+        /// for `INSERT INTO` statements based on the ISO SQL standard
+        #[derive(Debug, Copy, Clone)]
+        pub struct IsoSqlDefaultKeyword;
+
+        /// Indicates that a backend does not support `DEFAULT` value
+        /// expressions0for `INSERT INTO` statements
+        #[derive(Debug, Copy, Clone)]
+        pub struct DoesNotSupportDefaultKeyword;
+
+        impl SupportsDefaultKeyword for IsoSqlDefaultKeyword {}
+    }
+
+    /// This module contains all reusable options to configure
+    /// [`SqlDialect::BatchInsertSupport`]
+    pub mod batch_insert_support {
+        /// A marker trait indicating if batch insert statements
+        /// are supported for this backend or not
+        pub trait SupportsBatchInsert {}
+
+        /// Indicates that this backend does not support batch
+        /// insert statements.
+        /// In this case diesel will emulate batch insert support
+        /// by inserting each row on it's own
+        #[derive(Debug, Copy, Clone)]
+        pub struct DoesNotSupportBatchInsert;
+
+        /// Indicates that this backend supports postgres style
+        /// batch insert statements to insert multiple rows using one
+        /// insert statement
+        #[derive(Debug, Copy, Clone)]
+        pub struct PostgresLikeBatchInsertSupport;
+
+        impl SupportsBatchInsert for PostgresLikeBatchInsertSupport {}
+    }
+
+    /// This module contains all reusable options to configure
+    /// [`SqlDialect::DefaultValueClauseForInsert`]
+    pub mod default_value_clause {
+
+        /// Indicates that this backend uses the
+        /// `DEFAULT VALUES` syntax to specify
+        /// that a row consisting only of default
+        /// values should be inserted
+        #[derive(Debug, Clone, Copy)]
+        pub struct AnsiDefaultValueClause;
+    }
+
+    /// This module contains all reusable options to configure
+    /// [`SqlDialect::EmptyFromClauseSyntax`]
+    pub mod from_clause_syntax {
+
+        /// Indicates that this backend skips
+        /// the `FROM` clause in `SELECT` statements
+        /// if no table/view is queried
+        #[derive(Debug, Copy, Clone)]
+        pub struct AnsiSqlFromClauseSyntax;
+    }
+
+    /// This module contains all reusable options to configure
+    /// [`SqlDialect::ExistsSyntax`]
+    pub mod exists_syntax {
+
+        /// Indicates that this backend
+        /// treats `EXIST()` as function
+        /// like expression
+        #[derive(Debug, Copy, Clone)]
+        pub struct AnsiSqlExistsSyntax;
+    }
+
+    /// This module contains all reusable options to configure
+    /// [`SqlDialect::ArrayComparision`]
+    pub mod array_comparision {
+
+        /// Indicates that this backend requires a single bind
+        /// per array element in `IN()` and `NOT IN()` expression
+        #[derive(Debug, Copy, Clone)]
+        pub struct AnsiSqlArrayComparison;
+    }
+}
diff --git a/diesel/src/connection/transaction_manager.rs b/diesel/src/connection/transaction_manager.rs
index 5aa87478f68e..ca7f42b19ce3 100644
--- a/diesel/src/connection/transaction_manager.rs
+++ b/diesel/src/connection/transaction_manager.rs
@@ -1,4 +1,3 @@
-use crate::backend::UsesAnsiSavepointSyntax;
 use crate::connection::Connection;
 use crate::result::{DatabaseErrorKind, Error, QueryResult};
 
@@ -65,7 +64,6 @@ impl AnsiTransactionManager {
     pub fn begin_transaction_sql<Conn>(conn: &mut Conn, sql: &str) -> QueryResult<()>
     where
         Conn: Connection<TransactionManager = Self>,
-        Conn::Backend: UsesAnsiSavepointSyntax,
     {
         use crate::result::Error::AlreadyInTransaction;
 
@@ -81,7 +79,6 @@ impl AnsiTransactionManager {
 impl<Conn> TransactionManager<Conn> for AnsiTransactionManager
 where
     Conn: Connection<TransactionManager = Self>,
-    Conn::Backend: UsesAnsiSavepointSyntax,
 {
     type TransactionStateData = Self;
 
diff --git a/diesel/src/expression/array_comparison.rs b/diesel/src/expression/array_comparison.rs
index 7c8a3c8387c5..a6e69d0fa9d6 100644
--- a/diesel/src/expression/array_comparison.rs
+++ b/diesel/src/expression/array_comparison.rs
@@ -1,38 +1,36 @@
+use crate::backend::sql_dialect;
 use crate::backend::Backend;
+use crate::backend::SqlDialect;
+use crate::expression::bound::Bound;
 use crate::expression::subselect::Subselect;
 use crate::expression::*;
 use crate::query_builder::*;
 use crate::query_builder::{BoxedSelectStatement, SelectStatement};
 use crate::result::QueryResult;
 use crate::sql_types::Bool;
+use std::marker::PhantomData;
 
 #[derive(Debug, Copy, Clone, QueryId, ValidGrouping)]
 pub struct In<T, U> {
-    left: T,
-    values: U,
+    pub(crate) left: T,
+    pub(crate) values: U,
 }
 
 #[derive(Debug, Copy, Clone, QueryId, ValidGrouping)]
 pub struct NotIn<T, U> {
-    left: T,
-    values: U,
+    pub(crate) left: T,
+    pub(crate) values: U,
 }
 
 impl<T, U> In<T, U> {
     pub fn new(left: T, values: U) -> Self {
-        In {
-            left: left,
-            values: values,
-        }
+        In { left, values }
     }
 }
 
 impl<T, U> NotIn<T, U> {
     pub fn new(left: T, values: U) -> Self {
-        NotIn {
-            left: left,
-            values: values,
-        }
+        NotIn { left, values }
     }
 }
 
@@ -55,6 +53,18 @@ where
 impl<T, U, DB> QueryFragment<DB> for In<T, U>
 where
     DB: Backend,
+    Self: QueryFragment<DB, DB::ArrayComparision>,
+{
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::ArrayComparision>>::walk_ast(self, pass)
+    }
+}
+
+impl<T, U, DB> QueryFragment<DB, sql_dialect::array_comparision::AnsiSqlArrayComparison>
+    for In<T, U>
+where
+    DB: Backend
+        + SqlDialect<ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison>,
     T: QueryFragment<DB>,
     U: QueryFragment<DB> + MaybeEmpty,
 {
@@ -74,6 +84,18 @@ where
 impl<T, U, DB> QueryFragment<DB> for NotIn<T, U>
 where
     DB: Backend,
+    Self: QueryFragment<DB, DB::ArrayComparision>,
+{
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::ArrayComparision>>::walk_ast(self, pass)
+    }
+}
+
+impl<T, U, DB> QueryFragment<DB, sql_dialect::array_comparision::AnsiSqlArrayComparison>
+    for NotIn<T, U>
+where
+    DB: Backend
+        + SqlDialect<ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison>,
     T: QueryFragment<DB>,
     U: QueryFragment<DB> + MaybeEmpty,
 {
@@ -108,14 +130,10 @@ where
     T: AsExpression<ST>,
     ST: SqlType + TypedExpressionType,
 {
-    type InExpression = Many<T::Expression>;
+    type InExpression = Many<ST, T>;
 
     fn as_in_expression(self) -> Self::InExpression {
-        let expressions = self
-            .into_iter()
-            .map(<T as AsExpression<ST>>::as_expression)
-            .collect();
-        Many(expressions)
+        Many(self.into_iter().collect(), PhantomData)
     }
 }
 
@@ -149,37 +167,66 @@ where
     }
 }
 
-#[derive(Debug, Clone, ValidGrouping)]
-pub struct Many<T>(Vec<T>);
+#[derive(Debug, Clone)]
+pub struct Many<ST, I>(pub(crate) Vec<I>, PhantomData<ST>);
 
-impl<T: Expression> Expression for Many<T> {
-    type SqlType = T::SqlType;
+impl<ST, I, GB> ValidGrouping<GB> for Many<ST, I>
+where
+    ST: SingleValue,
+    I: AsExpression<ST>,
+    I::Expression: ValidGrouping<GB>,
+{
+    type IsAggregate = <I::Expression as ValidGrouping<GB>>::IsAggregate;
+}
+
+impl<ST, I> Expression for Many<ST, I>
+where
+    ST: TypedExpressionType,
+{
+    type SqlType = ST;
 }
 
-impl<T> MaybeEmpty for Many<T> {
+impl<ST, I> MaybeEmpty for Many<ST, I> {
     fn is_empty(&self) -> bool {
         self.0.is_empty()
     }
 }
 
-impl<T, QS> SelectableExpression<QS> for Many<T>
+impl<ST, I, QS> SelectableExpression<QS> for Many<ST, I>
 where
-    Many<T>: AppearsOnTable<QS>,
-    T: SelectableExpression<QS>,
+    Many<ST, I>: AppearsOnTable<QS>,
+    ST: SingleValue,
+    I: AsExpression<ST>,
+    <I as AsExpression<ST>>::Expression: SelectableExpression<QS>,
 {
 }
 
-impl<T, QS> AppearsOnTable<QS> for Many<T>
+impl<ST, I, QS> AppearsOnTable<QS> for Many<ST, I>
 where
-    Many<T>: Expression,
-    T: AppearsOnTable<QS>,
+    Many<ST, I>: Expression,
+    I: AsExpression<ST>,
+    ST: SingleValue,
+    <I as AsExpression<ST>>::Expression: SelectableExpression<QS>,
 {
 }
 
-impl<T, DB> QueryFragment<DB> for Many<T>
+impl<ST, I, DB> QueryFragment<DB> for Many<ST, I>
 where
+    Self: QueryFragment<DB, DB::ArrayComparision>,
     DB: Backend,
-    T: QueryFragment<DB>,
+{
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::ArrayComparision>>::walk_ast(self, pass)
+    }
+}
+
+impl<ST, I, DB> QueryFragment<DB, sql_dialect::array_comparision::AnsiSqlArrayComparison>
+    for Many<ST, I>
+where
+    DB: Backend
+        + SqlDialect<ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison>,
+    ST: SingleValue,
+    for<'a> Bound<ST, &'a I>: QueryFragment<DB>,
 {
     fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
         out.unsafe_to_cache_prepared();
@@ -190,13 +237,13 @@ where
             } else {
                 out.push_sql(", ");
             }
-            value.walk_ast(out.reborrow())?;
+            Bound::new(value).walk_ast(out.reborrow())?;
         }
         Ok(())
     }
 }
 
-impl<T> QueryId for Many<T> {
+impl<ST, I> QueryId for Many<ST, I> {
     type QueryId = ();
 
     const HAS_STATIC_QUERY_ID: bool = false;
diff --git a/diesel/src/expression/assume_not_null.rs b/diesel/src/expression/assume_not_null.rs
index 97eb13d7a010..756ecce9f99e 100644
--- a/diesel/src/expression/assume_not_null.rs
+++ b/diesel/src/expression/assume_not_null.rs
@@ -1,6 +1,7 @@
 use crate::backend::Backend;
 use crate::expression::TypedExpressionType;
 use crate::expression::*;
+use crate::query_builder::select_statement::NoFromClause;
 use crate::query_builder::*;
 use crate::query_source::joins::ToInnerJoin;
 use crate::result::QueryResult;
@@ -55,4 +56,7 @@ where
 {
 }
 
-impl<T> SelectableExpression<()> for AssumeNotNull<T> where Self: AppearsOnTable<()> {}
+impl<T> SelectableExpression<NoFromClause> for AssumeNotNull<T> where
+    Self: AppearsOnTable<NoFromClause>
+{
+}
diff --git a/diesel/src/expression/exists.rs b/diesel/src/expression/exists.rs
index 70bd7c7bfe48..08607550f904 100644
--- a/diesel/src/expression/exists.rs
+++ b/diesel/src/expression/exists.rs
@@ -1,4 +1,4 @@
-use crate::backend::Backend;
+use crate::backend::{sql_dialect, Backend, SqlDialect};
 use crate::expression::subselect::Subselect;
 use crate::expression::{AppearsOnTable, Expression, SelectableExpression, ValidGrouping};
 use crate::helper_types::exists;
@@ -50,27 +50,22 @@ where
     type IsAggregate = <Subselect<T, Bool> as ValidGrouping<GB>>::IsAggregate;
 }
 
-#[cfg(not(feature = "unstable"))]
 impl<T, DB> QueryFragment<DB> for Exists<T>
 where
     DB: Backend,
-    T: QueryFragment<DB>,
+    Self: QueryFragment<DB, DB::ExistsSyntax>,
 {
-    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
-        out.push_sql("EXISTS (");
-        self.0.walk_ast(out.reborrow())?;
-        out.push_sql(")");
-        Ok(())
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::ExistsSyntax>>::walk_ast(self, pass)
     }
 }
 
-#[cfg(feature = "unstable")]
-impl<T, DB> QueryFragment<DB> for Exists<T>
+impl<T, DB> QueryFragment<DB, sql_dialect::exists_syntax::AnsiSqlExistsSyntax> for Exists<T>
 where
-    DB: Backend,
+    DB: Backend + SqlDialect<ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax>,
     T: QueryFragment<DB>,
 {
-    default fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
+    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
         out.push_sql("EXISTS (");
         self.0.walk_ast(out.reborrow())?;
         out.push_sql(")");
diff --git a/diesel/src/expression/nullable.rs b/diesel/src/expression/nullable.rs
index 0e3bd016a2e3..d95a65b19638 100644
--- a/diesel/src/expression/nullable.rs
+++ b/diesel/src/expression/nullable.rs
@@ -1,6 +1,7 @@
 use crate::backend::Backend;
 use crate::expression::TypedExpressionType;
 use crate::expression::*;
+use crate::query_builder::select_statement::NoFromClause;
 use crate::query_builder::*;
 use crate::query_source::joins::ToInnerJoin;
 use crate::result::QueryResult;
@@ -68,4 +69,4 @@ where
 {
 }
 
-impl<T> SelectableExpression<()> for Nullable<T> where Self: AppearsOnTable<()> {}
+impl<T> SelectableExpression<NoFromClause> for Nullable<T> where Self: AppearsOnTable<NoFromClause> {}
diff --git a/diesel/src/expression/operators.rs b/diesel/src/expression/operators.rs
index c3c5ed1a04fb..de4eb8f04744 100644
--- a/diesel/src/expression/operators.rs
+++ b/diesel/src/expression/operators.rs
@@ -539,7 +539,7 @@ where
     type Values = ValuesClause<ColumnInsertValue<T, U>, T::Table>;
 
     fn values(self) -> Self::Values {
-        ValuesClause::new(ColumnInsertValue::new(self.left, self.right))
+        ValuesClause::new(ColumnInsertValue::new(self.right))
     }
 }
 
diff --git a/diesel/src/expression_methods/global_expression_methods.rs b/diesel/src/expression_methods/global_expression_methods.rs
index 508ae2016ef6..4c1dc047d95e 100644
--- a/diesel/src/expression_methods/global_expression_methods.rs
+++ b/diesel/src/expression_methods/global_expression_methods.rs
@@ -60,9 +60,8 @@ pub trait ExpressionMethods: Expression + Sized {
     /// in cases when a subquery is passed to the method, that
     /// query will use the cache (assuming the subquery
     /// itself is safe to cache).
-    /// On PostgreSQL, you should use
-    /// `eq(any())` instead. This method may change in the future to
-    /// automatically perform `= ANY` on PostgreSQL.
+    /// On PostgreSQL, this method automatically performs a `= ANY()`
+    /// query.
     ///
     /// # Example
     ///
@@ -103,9 +102,8 @@ pub trait ExpressionMethods: Expression + Sized {
     /// Creates a SQL `NOT IN` statement.
     ///
     /// Queries using this method will not be
-    /// placed in the prepared statement cache. On PostgreSQL, you should use
-    /// `ne(all())` instead. This method may change in the future to
-    /// automatically perform `!= ALL` on PostgreSQL.
+    /// placed in the prepared statement cache. On PostgreSQL, this
+    /// method automatically performs a `!= ALL()` query.
     ///
     /// # Example
     ///
diff --git a/diesel/src/insertable.rs b/diesel/src/insertable.rs
index 3051fac77ef5..e60160d9bf38 100644
--- a/diesel/src/insertable.rs
+++ b/diesel/src/insertable.rs
@@ -1,9 +1,11 @@
-use crate::backend::{Backend, SupportsDefaultKeyword};
+use std::marker::PhantomData;
+
+use crate::backend::{sql_dialect, Backend, SqlDialect};
 use crate::expression::grouped::Grouped;
 use crate::expression::{AppearsOnTable, Expression};
 use crate::query_builder::{
-    AstPass, BatchInsert, InsertStatement, QueryFragment, QueryId, UndecoratedInsertRecord,
-    ValuesClause,
+    AstPass, BatchInsert, InsertStatement, NoFromClause, QueryFragment, QueryId,
+    UndecoratedInsertRecord, ValuesClause,
 };
 use crate::query_source::{Column, Table};
 use crate::result::QueryResult;
@@ -119,13 +121,16 @@ pub trait InsertValues<T: Table, DB: Backend>: QueryFragment<DB> {
 #[derive(Debug, Copy, Clone, QueryId)]
 #[doc(hidden)]
 pub struct ColumnInsertValue<Col, Expr> {
-    col: Col,
     expr: Expr,
+    p: PhantomData<Col>,
 }
 
 impl<Col, Expr> ColumnInsertValue<Col, Expr> {
-    pub(crate) fn new(col: Col, expr: Expr) -> Self {
-        Self { col, expr }
+    pub(crate) fn new(expr: Expr) -> Self {
+        Self {
+            expr,
+            p: PhantomData,
+        }
     }
 }
 
@@ -150,9 +155,9 @@ impl<T> Default for DefaultableColumnInsertValue<T> {
 impl<Col, Expr, DB> InsertValues<Col::Table, DB>
     for DefaultableColumnInsertValue<ColumnInsertValue<Col, Expr>>
 where
-    DB: Backend + SupportsDefaultKeyword,
+    DB: Backend + SqlDialect<InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword>,
     Col: Column,
-    Expr: Expression<SqlType = Col::SqlType> + AppearsOnTable<()>,
+    Expr: Expression<SqlType = Col::SqlType> + AppearsOnTable<NoFromClause>,
     Self: QueryFragment<DB>,
 {
     fn column_names(&self, mut out: AstPass<DB>) -> QueryResult<()> {
@@ -165,7 +170,7 @@ impl<Col, Expr, DB> InsertValues<Col::Table, DB> for ColumnInsertValue<Col, Expr
 where
     DB: Backend,
     Col: Column,
-    Expr: Expression<SqlType = Col::SqlType> + AppearsOnTable<()>,
+    Expr: Expression<SqlType = Col::SqlType> + AppearsOnTable<NoFromClause>,
     Self: QueryFragment<DB>,
 {
     fn column_names(&self, mut out: AstPass<DB>) -> QueryResult<()> {
@@ -176,7 +181,17 @@ where
 
 impl<Expr, DB> QueryFragment<DB> for DefaultableColumnInsertValue<Expr>
 where
-    DB: Backend + SupportsDefaultKeyword,
+    DB: Backend,
+    Self: QueryFragment<DB, DB::InsertWithDefaultKeyword>,
+{
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::InsertWithDefaultKeyword>>::walk_ast(self, pass)
+    }
+}
+
+impl<Expr, DB> QueryFragment<DB, sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword> for DefaultableColumnInsertValue<Expr>
+where
+    DB: Backend + SqlDialect<InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword>,
     Expr: QueryFragment<DB>,
 {
     fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
@@ -205,7 +220,7 @@ impl<Col, Expr> InsertValues<Col::Table, crate::sqlite::Sqlite>
     for DefaultableColumnInsertValue<ColumnInsertValue<Col, Expr>>
 where
     Col: Column,
-    Expr: Expression<SqlType = Col::SqlType> + AppearsOnTable<()>,
+    Expr: Expression<SqlType = Col::SqlType> + AppearsOnTable<NoFromClause>,
     Self: QueryFragment<crate::sqlite::Sqlite>,
 {
     fn column_names(&self, mut out: AstPass<crate::sqlite::Sqlite>) -> QueryResult<()> {
@@ -217,8 +232,11 @@ where
 }
 
 #[cfg(feature = "sqlite")]
-impl<Col, Expr> QueryFragment<crate::sqlite::Sqlite>
-    for DefaultableColumnInsertValue<ColumnInsertValue<Col, Expr>>
+impl<Col, Expr>
+    QueryFragment<
+        crate::sqlite::Sqlite,
+        crate::backend::sql_dialect::default_keyword_for_insert::DoesNotSupportDefaultKeyword,
+    > for DefaultableColumnInsertValue<ColumnInsertValue<Col, Expr>>
 where
     Expr: QueryFragment<crate::sqlite::Sqlite>,
 {
@@ -300,15 +318,40 @@ where
     }
 }
 
-impl<T, V, Tab> Insertable<Tab> for Option<T>
+mod private {
+    // This helper exists to differentiate between
+    // Insertable implementations for tuples and for single values
+    #[allow(missing_debug_implementations)]
+    pub struct InsertableOptionHelper<T, V>(
+        pub(crate) Option<T>,
+        pub(crate) std::marker::PhantomData<V>,
+    );
+}
+
+pub(crate) use self::private::InsertableOptionHelper;
+
+impl<T, Tab, V> Insertable<Tab> for Option<T>
 where
     T: Insertable<Tab, Values = ValuesClause<V, Tab>>,
+    InsertableOptionHelper<T, V>: Insertable<Tab>,
+{
+    type Values = <InsertableOptionHelper<T, V> as Insertable<Tab>>::Values;
+
+    fn values(self) -> Self::Values {
+        InsertableOptionHelper(self, PhantomData).values()
+    }
+}
+
+impl<T, Tab, Expr, Col> Insertable<Tab> for InsertableOptionHelper<T, ColumnInsertValue<Col, Expr>>
+where
+    T: Insertable<Tab, Values = ValuesClause<ColumnInsertValue<Col, Expr>, Tab>>,
 {
-    type Values = ValuesClause<DefaultableColumnInsertValue<V>, Tab>;
+    type Values = ValuesClause<DefaultableColumnInsertValue<ColumnInsertValue<Col, Expr>>, Tab>;
 
     fn values(self) -> Self::Values {
         ValuesClause::new(
-            self.map(|v| DefaultableColumnInsertValue::Expression(Insertable::values(v).values))
+            self.0
+                .map(|v| DefaultableColumnInsertValue::Expression(Insertable::values(v).values))
                 .unwrap_or_default(),
         )
     }
diff --git a/diesel/src/lib.rs b/diesel/src/lib.rs
index 96211a2569a5..23795728f13a 100644
--- a/diesel/src/lib.rs
+++ b/diesel/src/lib.rs
@@ -91,9 +91,7 @@
 //! You can come ask for help at
 //! [gitter.im/diesel-rs/diesel](https://gitter.im/diesel-rs/diesel)
 
-#![cfg_attr(feature = "unstable", feature(specialization, trait_alias))]
-// For the `specialization` feature.
-#![cfg_attr(feature = "unstable", allow(incomplete_features))]
+#![cfg_attr(feature = "unstable", feature(trait_alias))]
 // Built-in Lints
 #![deny(warnings)]
 #![warn(
@@ -219,6 +217,12 @@ pub mod helper_types {
     /// Represents the return type of `.select(selection)`
     pub type Select<Source, Selection> = <Source as SelectDsl<Selection>>::Output;
 
+    /// Represents the return type of `diesel::select(selection)`
+    pub type BareSelect<T> = Select<
+        crate::query_builder::SelectStatement<crate::query_builder::select_statement::NoFromClause>,
+        T,
+    >;
+
     /// Represents the return type of `.filter(predicate)`
     pub type Filter<Source, Predicate> = <Source as FilterDsl<Predicate>>::Output;
 
diff --git a/diesel/src/macros/mod.rs b/diesel/src/macros/mod.rs
index cca129ce1cd9..46a813714bb2 100644
--- a/diesel/src/macros/mod.rs
+++ b/diesel/src/macros/mod.rs
@@ -734,7 +734,7 @@ macro_rules! __diesel_table_impl {
                 type Count = $crate::query_source::Once;
             }
 
-            impl $crate::query_source::AppearsInFromClause<table> for () {
+            impl $crate::query_source::AppearsInFromClause<table> for $crate::query_builder::NoFromClause {
                 type Count = $crate::query_source::Never;
             }
 
diff --git a/diesel/src/mysql/backend.rs b/diesel/src/mysql/backend.rs
index 39482b871747..7ddca27c59ef 100644
--- a/diesel/src/mysql/backend.rs
+++ b/diesel/src/mysql/backend.rs
@@ -77,5 +77,20 @@ impl TypeMetadata for Mysql {
     type MetadataLookup = ();
 }
 
-impl SupportsDefaultKeyword for Mysql {}
-impl UsesAnsiSavepointSyntax for Mysql {}
+impl SqlDialect for Mysql {
+    type ReturningClause = sql_dialect::returning_clause::DoesNotSupportReturningClause;
+
+    type OnConflictClause = sql_dialect::on_conflict_clause::DoesNotSupportOnConflictClause;
+
+    type InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword;
+    type BatchInsertSupport = sql_dialect::batch_insert_support::PostgresLikeBatchInsertSupport;
+    type DefaultValueClauseForInsert = MysqlStyleDefaultValueClause;
+
+    type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax;
+    type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax;
+
+    type ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison;
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct MysqlStyleDefaultValueClause;
diff --git a/diesel/src/mysql/mod.rs b/diesel/src/mysql/mod.rs
index 8f31612544fb..85fef049196f 100644
--- a/diesel/src/mysql/mod.rs
+++ b/diesel/src/mysql/mod.rs
@@ -4,7 +4,7 @@
 //! However, if you are writing code specifically to extend Diesel on
 //! MySQL, you may need to work with this module directly.
 
-mod backend;
+pub(crate) mod backend;
 mod connection;
 mod value;
 
diff --git a/diesel/src/mysql/query_builder/query_fragment_impls.rs b/diesel/src/mysql/query_builder/query_fragment_impls.rs
index fe3e6fdf3dcc..89036ec5d292 100644
--- a/diesel/src/mysql/query_builder/query_fragment_impls.rs
+++ b/diesel/src/mysql/query_builder/query_fragment_impls.rs
@@ -1,6 +1,6 @@
 use crate::mysql::Mysql;
 use crate::query_builder::locking_clause::{ForShare, ForUpdate, NoModifier, NoWait, SkipLocked};
-use crate::query_builder::{AstPass, QueryFragment};
+use crate::query_builder::{AstPass, DefaultValues, QueryFragment};
 use crate::result::QueryResult;
 
 impl QueryFragment<Mysql> for ForUpdate {
@@ -36,3 +36,10 @@ impl QueryFragment<Mysql> for NoWait {
         Ok(())
     }
 }
+
+impl QueryFragment<Mysql, crate::mysql::backend::MysqlStyleDefaultValueClause> for DefaultValues {
+    fn walk_ast(&self, mut out: AstPass<Mysql>) -> QueryResult<()> {
+        out.push_sql("() VALUES ()");
+        Ok(())
+    }
+}
diff --git a/diesel/src/pg/backend.rs b/diesel/src/pg/backend.rs
index fe573456583b..3fdf19e00916 100644
--- a/diesel/src/pg/backend.rs
+++ b/diesel/src/pg/backend.rs
@@ -97,8 +97,24 @@ impl TypeMetadata for Pg {
     type MetadataLookup = dyn PgMetadataLookup;
 }
 
-impl SupportsReturningClause for Pg {}
-impl SupportsOnConflictClause for Pg {}
-impl SupportsOnConflictTargetDecorations for Pg {}
-impl SupportsDefaultKeyword for Pg {}
-impl UsesAnsiSavepointSyntax for Pg {}
+impl SqlDialect for Pg {
+    type ReturningClause = sql_dialect::returning_clause::PgLikeReturningClause;
+
+    type OnConflictClause = PgOnConflictClaues;
+
+    type InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword;
+    type BatchInsertSupport = sql_dialect::batch_insert_support::PostgresLikeBatchInsertSupport;
+    type DefaultValueClauseForInsert = sql_dialect::default_value_clause::AnsiDefaultValueClause;
+
+    type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax;
+    type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax;
+    type ArrayComparision = PgStyleArrayComparision;
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct PgOnConflictClaues;
+
+impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for PgOnConflictClaues {}
+
+#[derive(Debug, Copy, Clone)]
+pub struct PgStyleArrayComparision;
diff --git a/diesel/src/pg/connection/mod.rs b/diesel/src/pg/connection/mod.rs
index 36b1e35994b7..db7ed60201a9 100644
--- a/diesel/src/pg/connection/mod.rs
+++ b/diesel/src/pg/connection/mod.rs
@@ -358,6 +358,16 @@ mod tests {
         assert_eq!(1, connection.statement_cache.len());
     }
 
+    #[test]
+    fn queries_containing_in_with_vec_are_cached() {
+        let connection = &mut connection();
+        let one_as_expr = 1.into_sql::<Integer>();
+        let query = crate::select(one_as_expr.eq_any(vec![1, 2, 3]));
+
+        assert_eq!(Ok(true), query.get_result(connection));
+        assert_eq!(1, connection.statement_cache.len());
+    }
+
     fn connection() -> PgConnection {
         crate::test_helpers::pg_connection_no_transaction()
     }
diff --git a/diesel/src/pg/expression/array_comparison.rs b/diesel/src/pg/expression/array_comparison.rs
index b37ad4627283..30cce1cdca50 100644
--- a/diesel/src/pg/expression/array_comparison.rs
+++ b/diesel/src/pg/expression/array_comparison.rs
@@ -26,6 +26,7 @@ use crate::sql_types::{Array, SqlType};
 /// assert_eq!(Ok(vec![sean, jim]), data.load(connection));
 /// # }
 /// ```
+#[deprecated(since = "2.0.0", note = "Use `ExpressionMethods::eq_any` instead")]
 pub fn any<ST, T>(vals: T) -> Any<T::Expression>
 where
     T: AsArrayExpression<ST>,
@@ -53,6 +54,7 @@ where
 /// assert_eq!(Ok(vec![tess]), data.load(connection));
 /// # }
 /// ```
+#[deprecated(since = "2.0.0", note = "Use `ExpressionMethods::ne_all` instead")]
 pub fn all<ST, T>(vals: T) -> All<T::Expression>
 where
     T: AsArrayExpression<ST>,
diff --git a/diesel/src/pg/expression/mod.rs b/diesel/src/pg/expression/mod.rs
index 2ccb192e8ae1..1e451e9ab91d 100644
--- a/diesel/src/pg/expression/mod.rs
+++ b/diesel/src/pg/expression/mod.rs
@@ -6,6 +6,7 @@
 
 pub(crate) mod array;
 #[doc(hidden)]
+#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
 pub mod array_comparison;
 pub(crate) mod expression_methods;
 pub mod extensions;
@@ -23,7 +24,9 @@ mod date_and_time;
 /// [`diesel::dsl`](crate::dsl) when compiled with the `feature =
 /// "postgres"` flag.
 pub mod dsl {
+    #[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
     #[doc(inline)]
+    #[allow(deprecated)]
     pub use super::array_comparison::{all, any};
 
     #[doc(inline)]
diff --git a/diesel/src/pg/metadata_lookup.rs b/diesel/src/pg/metadata_lookup.rs
index eee69384e075..c313d97f411d 100644
--- a/diesel/src/pg/metadata_lookup.rs
+++ b/diesel/src/pg/metadata_lookup.rs
@@ -96,7 +96,7 @@ fn lookup_type<T: Connection<Backend = Pg>>(
         .inner_join(pg_namespace::table)
         .filter(pg_type::typname.eq(&cache_key.type_name))
         .select((pg_type::oid, pg_type::typarray));
-    let nspname_filter = pg_namespace::nspname.eq(crate::dsl::any(search_schema));
+    let nspname_filter = pg_namespace::nspname.eq_any(search_schema);
 
     let metadata = if search_path_has_temp_schema {
         metadata_query
diff --git a/diesel/src/pg/mod.rs b/diesel/src/pg/mod.rs
index a988a729bb63..410473a1d730 100644
--- a/diesel/src/pg/mod.rs
+++ b/diesel/src/pg/mod.rs
@@ -7,7 +7,7 @@
 pub mod expression;
 pub mod types;
 
-mod backend;
+pub(crate) mod backend;
 mod connection;
 mod metadata_lookup;
 pub(crate) mod query_builder;
diff --git a/diesel/src/pg/query_builder/on_constraint.rs b/diesel/src/pg/query_builder/on_constraint.rs
index b1e267d20fe2..deef01e3e108 100644
--- a/diesel/src/pg/query_builder/on_constraint.rs
+++ b/diesel/src/pg/query_builder/on_constraint.rs
@@ -1,3 +1,4 @@
+use crate::pg::backend::PgOnConflictClaues;
 use crate::pg::Pg;
 use crate::query_builder::upsert::on_conflict_target::{ConflictTarget, OnConflictTarget};
 use crate::query_builder::*;
@@ -57,7 +58,7 @@ impl<'a> QueryId for OnConstraint<'a> {
     const HAS_STATIC_QUERY_ID: bool = false;
 }
 
-impl<'a> QueryFragment<Pg> for ConflictTarget<OnConstraint<'a>> {
+impl<'a> QueryFragment<Pg, PgOnConflictClaues> for ConflictTarget<OnConstraint<'a>> {
     fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
         out.unsafe_to_cache_prepared();
         out.push_sql(" ON CONSTRAINT ");
diff --git a/diesel/src/pg/query_builder/query_fragment_impls.rs b/diesel/src/pg/query_builder/query_fragment_impls.rs
index e38745b9e089..38c6ae5196af 100644
--- a/diesel/src/pg/query_builder/query_fragment_impls.rs
+++ b/diesel/src/pg/query_builder/query_fragment_impls.rs
@@ -1,9 +1,16 @@
+use crate::expression::array_comparison::{In, Many, MaybeEmpty, NotIn};
+use crate::expression::AsExpression;
+use crate::pg::backend::PgStyleArrayComparision;
+use crate::pg::types::sql_types::Array;
 use crate::pg::Pg;
 use crate::query_builder::locking_clause::{
     ForKeyShare, ForNoKeyUpdate, ForShare, ForUpdate, NoModifier, NoWait, SkipLocked,
 };
+use crate::query_builder::upsert::on_conflict_target_decorations::DecoratedConflictTarget;
 use crate::query_builder::{AstPass, QueryFragment};
 use crate::result::QueryResult;
+use crate::serialize::ToSql;
+use crate::sql_types::{HasSqlType, SingleValue};
 
 impl QueryFragment<Pg> for ForUpdate {
     fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
@@ -52,3 +59,56 @@ impl QueryFragment<Pg> for NoWait {
         Ok(())
     }
 }
+
+impl<T, U> QueryFragment<Pg, PgStyleArrayComparision> for In<T, U>
+where
+    T: QueryFragment<Pg>,
+    U: QueryFragment<Pg> + MaybeEmpty,
+{
+    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
+        self.left.walk_ast(out.reborrow())?;
+        out.push_sql(" = ANY(");
+        self.values.walk_ast(out.reborrow())?;
+        out.push_sql(")");
+        Ok(())
+    }
+}
+
+impl<T, U> QueryFragment<Pg, PgStyleArrayComparision> for NotIn<T, U>
+where
+    T: QueryFragment<Pg>,
+    U: QueryFragment<Pg> + MaybeEmpty,
+{
+    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
+        self.left.walk_ast(out.reborrow())?;
+        out.push_sql(" != ALL(");
+        self.values.walk_ast(out.reborrow())?;
+        out.push_sql(")");
+        Ok(())
+    }
+}
+
+impl<ST, I> QueryFragment<Pg, PgStyleArrayComparision> for Many<ST, I>
+where
+    ST: SingleValue,
+    for<'a> &'a [I]: ToSql<Array<ST>, Pg>,
+    Pg: HasSqlType<ST>,
+{
+    fn walk_ast(&self, out: AstPass<Pg>) -> QueryResult<()> {
+        let values = &self.0 as &[I];
+        <_ as AsExpression<Array<ST>>>::as_expression(values).walk_ast(out)
+    }
+}
+
+impl<T, U> QueryFragment<Pg, crate::pg::backend::PgOnConflictClaues>
+    for DecoratedConflictTarget<T, U>
+where
+    T: QueryFragment<Pg>,
+    U: QueryFragment<Pg>,
+{
+    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
+        self.target.walk_ast(out.reborrow())?;
+        self.where_clause.walk_ast(out.reborrow())?;
+        Ok(())
+    }
+}
diff --git a/diesel/src/pg/types/numeric.rs b/diesel/src/pg/types/numeric.rs
index 980b621b37d9..75c4d8a6fffc 100644
--- a/diesel/src/pg/types/numeric.rs
+++ b/diesel/src/pg/types/numeric.rs
@@ -322,7 +322,6 @@ mod bigdecimal {
         }
 
         #[test]
-        #[cfg(feature = "unstable")]
         fn pg_numeric_to_bigdecimal_works() {
             let expected = BigDecimal::from_str("123.456").unwrap();
             let pg_numeric = PgNumeric::Positive {
diff --git a/diesel/src/query_builder/functions.rs b/diesel/src/query_builder/functions.rs
index b80400b81c38..c9c58b55c5fb 100644
--- a/diesel/src/query_builder/functions.rs
+++ b/diesel/src/query_builder/functions.rs
@@ -3,7 +3,6 @@ use super::insert_statement::{Insert, InsertOrIgnore, Replace};
 use super::{
     IncompleteInsertStatement, IntoUpdateTarget, SelectStatement, SqlQuery, UpdateStatement,
 };
-use crate::dsl::Select;
 use crate::expression::Expression;
 use crate::query_dsl::methods::SelectDsl;
 
@@ -458,12 +457,12 @@ pub fn insert_or_ignore_into<T>(target: T) -> IncompleteInsertStatement<T, Inser
 /// Creates a bare select statement, with no from clause. Primarily used for
 /// testing diesel itself, but likely useful for third party crates as well. The
 /// given expressions must be selectable from anywhere.
-pub fn select<T>(expression: T) -> Select<SelectStatement<()>, T>
+pub fn select<T>(expression: T) -> crate::dsl::BareSelect<T>
 where
     T: Expression,
-    SelectStatement<()>: SelectDsl<T>,
+    SelectStatement<crate::query_builder::select_statement::NoFromClause>: SelectDsl<T>,
 {
-    SelectStatement::simple(()).select(expression)
+    SelectStatement::simple(crate::query_builder::select_statement::NoFromClause).select(expression)
 }
 
 /// Creates a `REPLACE` statement.
diff --git a/diesel/src/query_builder/insert_statement/batch_insert.rs b/diesel/src/query_builder/insert_statement/batch_insert.rs
index c8e9e290664f..b8fc15c4cb45 100644
--- a/diesel/src/query_builder/insert_statement/batch_insert.rs
+++ b/diesel/src/query_builder/insert_statement/batch_insert.rs
@@ -1,13 +1,14 @@
 use super::ValuesClause;
-use crate::backend::{Backend, SupportsDefaultKeyword};
+use crate::backend::{sql_dialect, Backend, SqlDialect};
 use crate::insertable::CanInsertInSingleQuery;
 use crate::query_builder::{AstPass, QueryFragment, QueryId};
 use crate::{Insertable, QueryResult};
 use std::marker::PhantomData;
 
+#[doc(hidden)]
 #[derive(Debug)]
 pub struct BatchInsert<V, Tab, QId, const STABLE_QUERY_ID: bool> {
-    pub(crate) values: V,
+    pub values: V,
     _marker: PhantomData<(QId, Tab)>,
 }
 
@@ -32,7 +33,7 @@ impl<T, Table, QId, DB, const HAS_STATIC_QUERY_ID: bool> CanInsertInSingleQuery<
     for BatchInsert<T, Table, QId, HAS_STATIC_QUERY_ID>
 where
     T: CanInsertInSingleQuery<DB>,
-    DB: Backend + SupportsDefaultKeyword,
+DB: Backend+ SqlDialect<InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword>
 {
     fn rows_to_insert(&self) -> Option<usize> {
         self.values.rows_to_insert()
@@ -41,7 +42,7 @@ where
 
 impl<T, DB, const N: usize> CanInsertInSingleQuery<DB> for [T; N]
 where
-    DB: Backend + SupportsDefaultKeyword,
+DB: Backend+ SqlDialect<InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword>
 {
     fn rows_to_insert(&self) -> Option<usize> {
         Some(N)
@@ -50,7 +51,7 @@ where
 
 impl<T, DB, const N: usize> CanInsertInSingleQuery<DB> for Box<[T; N]>
 where
-    DB: Backend + SupportsDefaultKeyword,
+    DB: Backend+ SqlDialect<InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword>
 {
     fn rows_to_insert(&self) -> Option<usize> {
         Some(N)
@@ -59,7 +60,7 @@ where
 
 impl<T, DB> CanInsertInSingleQuery<DB> for [T]
 where
-    DB: Backend + SupportsDefaultKeyword,
+    DB: Backend+ SqlDialect<InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword>
 {
     fn rows_to_insert(&self) -> Option<usize> {
         Some(self.len())
@@ -68,13 +69,14 @@ where
 
 impl<T, DB> CanInsertInSingleQuery<DB> for Vec<T>
 where
-    DB: Backend + SupportsDefaultKeyword,
+    DB: Backend+ SqlDialect<InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword>,
 {
     fn rows_to_insert(&self) -> Option<usize> {
         Some(self.len())
     }
 }
 
+#[doc(hidden)]
 pub trait AsValueIterator<Tab> {
     type Item;
 
@@ -179,6 +181,7 @@ impl<'b, T, Tab> AsValueIterator<Tab> for &'b [T] {
 // For this case this is essentially only that `Self::Values` implement `QueryFragment`
 // This allows us to unify all that behind a single trait bound in the
 // `QueryFragment` impl below
+#[doc(hidden)]
 pub trait InsertableQueryfragment<Tab, DB>
 where
     Self: Insertable<Tab>,
@@ -214,6 +217,7 @@ where
     }
 }
 
+#[doc(hidden)]
 pub trait IsValuesClause<DB: Backend> {
     type Inner: QueryFragment<DB>;
 
@@ -232,10 +236,26 @@ where
     }
 }
 
-impl<Tab, DB, T, V, QId, const HAS_STATIC_QUERY_ID: bool> QueryFragment<DB>
+impl<Tab, DB, V, QId, const HAS_STATIC_QUERY_ID: bool> QueryFragment<DB>
     for BatchInsert<V, Tab, QId, HAS_STATIC_QUERY_ID>
 where
-    DB: Backend + SupportsDefaultKeyword,
+    DB: Backend,
+    Self: QueryFragment<DB, DB::BatchInsertSupport>,
+{
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::BatchInsertSupport>>::walk_ast(self, pass)
+    }
+}
+
+impl<Tab, DB, T, V, QId, const HAS_STATIC_QUERY_ID: bool>
+    QueryFragment<DB, sql_dialect::batch_insert_support::PostgresLikeBatchInsertSupport>
+    for BatchInsert<V, Tab, QId, HAS_STATIC_QUERY_ID>
+where
+    DB: Backend
+        + SqlDialect<
+            BatchInsertSupport = sql_dialect::batch_insert_support::PostgresLikeBatchInsertSupport,
+        >,
+    DB::InsertWithDefaultKeyword: sql_dialect::default_keyword_for_insert::SupportsDefaultKeyword,
     V: AsValueIterator<Tab, Item = T>,
     for<'a> &'a T: InsertableQueryfragment<Tab, DB>,
 {
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 b0398502964d..d896f6e62224 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
@@ -1,12 +1,16 @@
-use super::batch_insert::AsValueIterator;
 use super::{BatchInsert, InsertStatement};
 use crate::connection::Connection;
 use crate::insertable::Insertable;
+use crate::insertable::{CanInsertInSingleQuery, ColumnInsertValue, DefaultableColumnInsertValue};
+use crate::prelude::*;
 use crate::query_builder::returning_clause::NoReturningClause;
-use crate::query_builder::{DebugQuery, QueryFragment, QueryId};
+use crate::query_builder::{
+    AsValueIterator, AstPass, InsertableQueryfragment, QueryId, ValuesClause,
+};
+use crate::query_builder::{DebugQuery, QueryFragment};
 use crate::query_dsl::methods::ExecuteDsl;
 use crate::sqlite::Sqlite;
-use crate::{QueryResult, SqliteConnection, Table};
+use crate::{QueryResult, Table};
 use std::fmt::{self, Debug, Display, Write};
 
 pub trait SqliteInsertableQueryfragment<Tab, Op, C>
@@ -52,8 +56,204 @@ where
     }
 }
 
-impl<T, V, QId, Op, C, const STATIC_QUERY_ID: bool> ExecuteDsl<C, Sqlite>
+pub trait DebugQueryHelper<ContainsDefaultableValue> {
+    fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
+    fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
+}
+
+impl<'a, T, V, QId, Op, const STATIC_QUERY_ID: bool> DebugQueryHelper<Yes>
+    for DebugQuery<'a, InsertStatement<T, BatchInsert<V, T, QId, STATIC_QUERY_ID>, Op>, Sqlite>
+where
+    V: AsValueIterator<T>,
+    for<'b> &'b V::Item: SqliteInsertableQueryfragment<T, Op, SqliteConnection>,
+    T: Copy,
+    Op: Copy,
+{
+    fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut statements = vec![String::from("BEGIN")];
+        for record in self.query.records.values.as_value_iter() {
+            let mut out = String::new();
+            <&V::Item as SqliteInsertableQueryfragment<T, Op, SqliteConnection>>::write_debug_query(record, &mut out, self.query.target, self.query.operator)?;
+            statements.push(out);
+        }
+        statements.push("COMMIT".into());
+
+        f.debug_struct("Query")
+            .field("sql", &statements)
+            .field("binds", &[] as &[i32; 0])
+            .finish()
+    }
+
+    fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        writeln!(f, "BEGIN;")?;
+        for record in self.query.records.values.as_value_iter() {
+            <&V::Item as SqliteInsertableQueryfragment<T, Op, SqliteConnection>>::write_debug_query(record, f, self.query.target, self.query.operator)?;
+            writeln!(f)?;
+        }
+        writeln!(f, "COMMIT;")?;
+        Ok(())
+    }
+}
+
+impl<'a, T, V, QId, Op, const STATIC_QUERY_ID: bool> DebugQueryHelper<No>
+    for DebugQuery<'a, InsertStatement<T, BatchInsert<V, T, QId, STATIC_QUERY_ID>, Op>, Sqlite>
+where
+    T: Copy,
+    Op: Copy,
+    DebugQuery<
+        'a,
+        InsertStatement<T, SqliteBatchInsertWrapper<V, T, QId, STATIC_QUERY_ID>, Op>,
+        Sqlite,
+    >: Debug + Display,
+{
+    fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let value = unsafe {
+            // This cast is safe as `SqliteBatchInsertWrapper` is #[repr(transparent)]
+            &*(self as *const DebugQuery<
+                InsertStatement<T, BatchInsert<V, T, QId, STATIC_QUERY_ID>, Op>,
+                Sqlite,
+            >
+                as *const DebugQuery<
+                    InsertStatement<T, SqliteBatchInsertWrapper<V, T, QId, STATIC_QUERY_ID>, Op>,
+                    Sqlite,
+                >)
+        };
+        <_ as Debug>::fmt(value, f)
+    }
+
+    fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let value = unsafe {
+            // This cast is safe as `SqliteBatchInsertWrapper` is #[repr(transparent)]
+            &*(self as *const DebugQuery<
+                InsertStatement<T, BatchInsert<V, T, QId, STATIC_QUERY_ID>, Op>,
+                Sqlite,
+            >
+                as *const DebugQuery<
+                    InsertStatement<T, SqliteBatchInsertWrapper<V, T, QId, STATIC_QUERY_ID>, Op>,
+                    Sqlite,
+                >)
+        };
+        <_ as Display>::fmt(value, f)
+    }
+}
+
+impl<'a, T, V, QId, Op, O, const STATIC_QUERY_ID: bool> Display
+    for DebugQuery<'a, InsertStatement<T, BatchInsert<V, T, QId, STATIC_QUERY_ID>, Op>, Sqlite>
+where
+    V: AsValueIterator<T>,
+    V::Item: Insertable<T>,
+    <V::Item as Insertable<T>>::Values: ContainsDefaultableValue<Out = O>,
+    Self: DebugQueryHelper<O>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.fmt_display(f)
+    }
+}
+
+impl<'a, T, V, QId, Op, O, const STATIC_QUERY_ID: bool> Debug
+    for DebugQuery<'a, InsertStatement<T, BatchInsert<V, T, QId, STATIC_QUERY_ID>, Op>, Sqlite>
+where
+    V: AsValueIterator<T>,
+    V::Item: Insertable<T>,
+    <V::Item as Insertable<T>>::Values: ContainsDefaultableValue<Out = O>,
+    Self: DebugQueryHelper<O>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.fmt_debug(f)
+    }
+}
+
+#[allow(missing_debug_implementations, missing_copy_implementations)]
+pub struct Yes;
+
+impl Default for Yes {
+    fn default() -> Self {
+        Yes
+    }
+}
+
+#[allow(missing_debug_implementations, missing_copy_implementations)]
+pub struct No;
+
+impl Default for No {
+    fn default() -> Self {
+        No
+    }
+}
+
+pub trait Any<Rhs> {
+    type Out: Any<Yes> + Any<No>;
+}
+
+impl Any<No> for No {
+    type Out = No;
+}
+
+impl Any<Yes> for No {
+    type Out = Yes;
+}
+
+impl Any<No> for Yes {
+    type Out = Yes;
+}
+
+impl Any<Yes> for Yes {
+    type Out = Yes;
+}
+
+pub trait ContainsDefaultableValue {
+    type Out: Any<Yes> + Any<No>;
+}
+
+impl<C, B> ContainsDefaultableValue for ColumnInsertValue<C, B> {
+    type Out = No;
+}
+
+impl<I> ContainsDefaultableValue for DefaultableColumnInsertValue<I> {
+    type Out = Yes;
+}
+
+impl<I, const SIZE: usize> ContainsDefaultableValue for [I; SIZE]
+where
+    I: ContainsDefaultableValue,
+{
+    type Out = I::Out;
+}
+
+impl<I, T> ContainsDefaultableValue for ValuesClause<I, T>
+where
+    I: ContainsDefaultableValue,
+{
+    type Out = I::Out;
+}
+
+impl<'a, T> ContainsDefaultableValue for &'a T
+where
+    T: ContainsDefaultableValue,
+{
+    type Out = T::Out;
+}
+
+impl<V, T, QId, C, Op, O, const STATIC_QUERY_ID: bool> ExecuteDsl<C, Sqlite>
     for InsertStatement<T, BatchInsert<V, T, QId, STATIC_QUERY_ID>, Op>
+where
+    C: Connection<Backend = Sqlite>,
+    V: AsValueIterator<T>,
+    V::Item: Insertable<T>,
+    <V::Item as Insertable<T>>::Values: ContainsDefaultableValue<Out = O>,
+    O: Default,
+    (O, Self): ExecuteDsl<C, Sqlite>,
+{
+    fn execute(query: Self, conn: &mut C) -> QueryResult<usize> {
+        <(O, Self) as ExecuteDsl<C, Sqlite>>::execute((O::default(), query), conn)
+    }
+}
+
+impl<V, T, QId, C, Op, const STATIC_QUERY_ID: bool> ExecuteDsl<C, Sqlite>
+    for (
+        Yes,
+        InsertStatement<T, BatchInsert<V, T, QId, STATIC_QUERY_ID>, Op>,
+    )
 where
     C: Connection<Backend = Sqlite>,
     V: AsValueIterator<T>,
@@ -62,7 +262,7 @@ where
     T::FromClause: QueryFragment<Sqlite>,
     Op: Copy + QueryId,
 {
-    fn execute(query: Self, conn: &mut C) -> QueryResult<usize> {
+    fn execute((Yes, query): Self, conn: &mut C) -> QueryResult<usize> {
         conn.transaction(|conn| {
             let mut result = 0;
             for record in query.records.values.as_value_iter() {
@@ -79,45 +279,207 @@ where
     }
 }
 
-impl<'a, T, V, QId, Op, const STATIC_QUERY_ID: bool> Display
-    for DebugQuery<'a, InsertStatement<T, BatchInsert<V, T, QId, STATIC_QUERY_ID>, Op>, Sqlite>
+#[allow(missing_debug_implementations, missing_copy_implementations)]
+#[repr(transparent)]
+pub struct SqliteBatchInsertWrapper<V, T, QId, const STATIC_QUERY_ID: bool>(
+    BatchInsert<V, T, QId, STATIC_QUERY_ID>,
+);
+
+impl<V, Tab, T, QId, const STATIC_QUERY_ID: bool> QueryFragment<Sqlite>
+    for SqliteBatchInsertWrapper<V, Tab, QId, STATIC_QUERY_ID>
 where
-    V: AsValueIterator<T>,
-    for<'b> &'b V::Item: SqliteInsertableQueryfragment<T, Op, SqliteConnection>,
-    T: Copy,
-    Op: Copy,
+    V: AsValueIterator<Tab, Item = T>,
+    for<'a> &'a T: InsertableQueryfragment<Tab, Sqlite>,
 {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        writeln!(f, "BEGIN;")?;
-        for record in self.query.records.values.as_value_iter() {
-            <&V::Item as SqliteInsertableQueryfragment<T, Op, SqliteConnection>>::write_debug_query(record, f, self.query.target, self.query.operator)?;
-            writeln!(f)?;
+    fn walk_ast(&self, mut out: AstPass<Sqlite>) -> QueryResult<()> {
+        if !STATIC_QUERY_ID {
+            out.unsafe_to_cache_prepared();
+        }
+
+        let mut values = self.0.values.as_value_iter();
+        if let Some(value) = values.next() {
+            <&T as InsertableQueryfragment<Tab, Sqlite>>::walk_ast_helper_with_value_clause(
+                value,
+                out.reborrow(),
+            )?;
+        }
+        for value in values {
+            out.push_sql(", (");
+            <&T as InsertableQueryfragment<Tab, Sqlite>>::walk_ast_helper_without_value_clause(
+                value,
+                out.reborrow(),
+            )?;
+            out.push_sql(")");
         }
-        writeln!(f, "COMMIT;")?;
         Ok(())
     }
 }
 
-impl<'a, T, V, QId, Op, const STATIC_QUERY_ID: bool> Debug
-    for DebugQuery<'a, InsertStatement<T, BatchInsert<V, T, QId, STATIC_QUERY_ID>, Op>, Sqlite>
+#[allow(missing_copy_implementations, missing_debug_implementations)]
+#[repr(transparent)]
+pub struct SqliteCanInsertInSingleQueryHelper<T: ?Sized>(T);
+
+impl<V, T, QId, const STATIC_QUERY_ID: bool> CanInsertInSingleQuery<Sqlite>
+    for SqliteBatchInsertWrapper<V, T, QId, STATIC_QUERY_ID>
 where
+    // We constrain that here on an internal helper type
+    // to make sure that this does not accidently leak
+    // so that noone does really implement normal batch
+    // insert for inserts with default values here
+    SqliteCanInsertInSingleQueryHelper<V>: CanInsertInSingleQuery<Sqlite>,
     V: AsValueIterator<T>,
-    for<'b> &'b V::Item: SqliteInsertableQueryfragment<T, Op, SqliteConnection>,
-    T: Copy,
-    Op: Copy,
+    V::Item: Insertable<T>,
+    <V::Item as Insertable<T>>::Values: ContainsDefaultableValue<Out = No>,
 {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let mut statements = vec![String::from("BEGIN")];
-        for record in self.query.records.values.as_value_iter() {
-            let mut out = String::new();
-            <&V::Item as SqliteInsertableQueryfragment<T, Op, SqliteConnection>>::write_debug_query(record, &mut out, self.query.target, self.query.operator)?;
-            statements.push(out);
+    fn rows_to_insert(&self) -> Option<usize> {
+        let values = &self.0.values;
+        let values = unsafe {
+            // This cast is safe as `SqliteCanInsertInSingleQueryHelper` is #[repr(transparent)]
+            &*(values as *const V as *const SqliteCanInsertInSingleQueryHelper<V>)
+        };
+        values.rows_to_insert()
+    }
+}
+
+impl<T, const N: usize> CanInsertInSingleQuery<Sqlite>
+    for SqliteCanInsertInSingleQueryHelper<[T; N]>
+{
+    fn rows_to_insert(&self) -> Option<usize> {
+        Some(N)
+    }
+}
+
+impl<T, const N: usize> CanInsertInSingleQuery<Sqlite>
+    for SqliteCanInsertInSingleQueryHelper<Box<[T; N]>>
+{
+    fn rows_to_insert(&self) -> Option<usize> {
+        Some(N)
+    }
+}
+
+impl<T> CanInsertInSingleQuery<Sqlite> for SqliteCanInsertInSingleQueryHelper<[T]> {
+    fn rows_to_insert(&self) -> Option<usize> {
+        Some(self.0.len())
+    }
+}
+
+impl<'a, T> CanInsertInSingleQuery<Sqlite> for SqliteCanInsertInSingleQueryHelper<&'a [T]> {
+    fn rows_to_insert(&self) -> Option<usize> {
+        Some(self.0.len())
+    }
+}
+
+impl<T> CanInsertInSingleQuery<Sqlite> for SqliteCanInsertInSingleQueryHelper<Vec<T>> {
+    fn rows_to_insert(&self) -> Option<usize> {
+        Some(self.0.len())
+    }
+}
+
+impl<T> CanInsertInSingleQuery<Sqlite> for SqliteCanInsertInSingleQueryHelper<T>
+where
+    T: CanInsertInSingleQuery<Sqlite>,
+{
+    fn rows_to_insert(&self) -> Option<usize> {
+        self.0.rows_to_insert()
+    }
+}
+
+impl<V, T, QId, const STATIC_QUERY_ID: bool> QueryId
+    for SqliteBatchInsertWrapper<V, T, QId, STATIC_QUERY_ID>
+where
+    BatchInsert<V, T, QId, STATIC_QUERY_ID>: QueryId,
+{
+    type QueryId = <BatchInsert<V, T, QId, STATIC_QUERY_ID> as QueryId>::QueryId;
+
+    const HAS_STATIC_QUERY_ID: bool =
+        <BatchInsert<V, T, QId, STATIC_QUERY_ID> as QueryId>::HAS_STATIC_QUERY_ID;
+}
+
+impl<V, T, QId, C, Op, const STATIC_QUERY_ID: bool> ExecuteDsl<C, Sqlite>
+    for (
+        No,
+        InsertStatement<T, BatchInsert<V, T, QId, STATIC_QUERY_ID>, Op>,
+    )
+where
+    C: Connection<Backend = Sqlite>,
+    T: Table + QueryId,
+    T::FromClause: QueryFragment<Sqlite>,
+    Op: QueryFragment<Sqlite> + QueryId,
+    SqliteBatchInsertWrapper<V, T, QId, STATIC_QUERY_ID>:
+        QueryFragment<Sqlite> + QueryId + CanInsertInSingleQuery<Sqlite>,
+{
+    fn execute((No, query): Self, conn: &mut C) -> QueryResult<usize> {
+        let query = InsertStatement {
+            records: SqliteBatchInsertWrapper(query.records),
+            operator: query.operator,
+            target: query.target,
+            returning: query.returning,
+        };
+        query.execute(conn)
+    }
+}
+
+macro_rules! tuple_impls {
+        ($(
+            $Tuple:tt {
+                $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
+            }
+        )+) => {
+            $(
+                impl_contains_defaultable_value!($($T,)*);
+            )*
         }
-        statements.push("COMMIT".into());
+    }
 
-        f.debug_struct("Query")
-            .field("sql", &statements)
-            .field("binds", &[] as &[i32; 0])
-            .finish()
+macro_rules! impl_contains_defaultable_value {
+    (
+        @build
+        start_ts = [$($ST: ident,)*],
+        ts = [$T1: ident,],
+        bounds = [$($bounds: tt)*],
+        out = [$($out: tt)*],
+    )=> {
+        impl<$($ST,)*> ContainsDefaultableValue for ($($ST,)*)
+        where
+            $($ST: ContainsDefaultableValue,)*
+            $($bounds)*
+            $T1::Out: Any<$($out)*>,
+        {
+            type Out = <$T1::Out as Any<$($out)*>>::Out;
+        }
+
+    };
+    (
+        @build
+        start_ts = [$($ST: ident,)*],
+        ts = [$T1: ident, $($T: ident,)+],
+        bounds = [$($bounds: tt)*],
+        out = [$($out: tt)*],
+    )=> {
+        impl_contains_defaultable_value! {
+            @build
+            start_ts = [$($ST,)*],
+            ts = [$($T,)*],
+            bounds = [$($bounds)* $T1::Out: Any<$($out)*>,],
+            out = [<$T1::Out as Any<$($out)*>>::Out],
+        }
+    };
+    ($T1: ident, $($T: ident,)+) => {
+        impl_contains_defaultable_value! {
+            @build
+            start_ts = [$T1, $($T,)*],
+            ts = [$($T,)*],
+            bounds = [],
+            out = [$T1::Out],
+        }
+    };
+    ($T1: ident,) => {
+        impl<$T1> ContainsDefaultableValue for ($T1,)
+        where $T1: ContainsDefaultableValue,
+        {
+            type Out = <$T1 as ContainsDefaultableValue>::Out;
+        }
     }
 }
+
+__diesel_for_each_tuple!(tuple_impls);
diff --git a/diesel/src/query_builder/insert_statement/mod.rs b/diesel/src/query_builder/insert_statement/mod.rs
index cc60f8a20ef7..187174fb4c66 100644
--- a/diesel/src/query_builder/insert_statement/mod.rs
+++ b/diesel/src/query_builder/insert_statement/mod.rs
@@ -2,15 +2,16 @@ mod batch_insert;
 mod column_list;
 mod insert_from_select;
 
-pub(crate) use self::batch_insert::BatchInsert;
+pub use self::batch_insert::{
+    AsValueIterator, BatchInsert, InsertableQueryfragment, IsValuesClause,
+};
 pub(crate) use self::column_list::ColumnList;
 pub(crate) use self::insert_from_select::InsertFromSelect;
 
-use std::any::*;
 use std::marker::PhantomData;
 
 use super::returning_clause::*;
-use crate::backend::Backend;
+use crate::backend::{sql_dialect, Backend, SqlDialect};
 use crate::expression::grouped::Grouped;
 use crate::expression::operators::Eq;
 use crate::expression::{Expression, NonAggregate, SelectableExpression};
@@ -388,20 +389,22 @@ impl<'a, Tab> Insertable<Tab> for &'a DefaultValues {
 
 impl<DB> QueryFragment<DB> for DefaultValues
 where
-    DB: Backend + Any,
+    DB: Backend,
+    Self: QueryFragment<DB, DB::DefaultValueClauseForInsert>,
 {
-    #[cfg(feature = "mysql")]
-    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
-        // This can be less hacky once stabilization lands
-        if TypeId::of::<DB>() == TypeId::of::<crate::mysql::Mysql>() {
-            out.push_sql("() VALUES ()");
-        } else {
-            out.push_sql("DEFAULT VALUES");
-        }
-        Ok(())
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::DefaultValueClauseForInsert>>::walk_ast(self, pass)
     }
+}
 
-    #[cfg(not(feature = "mysql"))]
+impl<DB> QueryFragment<DB, sql_dialect::default_value_clause::AnsiDefaultValueClause>
+    for DefaultValues
+where
+    DB: Backend
+        + SqlDialect<
+            DefaultValueClauseForInsert = sql_dialect::default_value_clause::AnsiDefaultValueClause,
+        >,
+{
     fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
         out.push_sql("DEFAULT VALUES");
         Ok(())
diff --git a/diesel/src/query_builder/mod.rs b/diesel/src/query_builder/mod.rs
index 4b4b6d9ce245..4f52cbbb1407 100644
--- a/diesel/src/query_builder/mod.rs
+++ b/diesel/src/query_builder/mod.rs
@@ -29,7 +29,7 @@ pub(crate) mod offset_clause;
 pub(crate) mod order_clause;
 mod returning_clause;
 pub(crate) mod select_clause;
-mod select_statement;
+pub(crate) mod select_statement;
 mod sql_query;
 mod update_statement;
 pub(crate) mod upsert;
@@ -39,6 +39,10 @@ pub use self::ast_pass::AstPass;
 pub use self::bind_collector::BindCollector;
 pub use self::debug_query::DebugQuery;
 pub use self::delete_statement::{BoxedDeleteStatement, DeleteStatement};
+#[doc(hidden)]
+pub use self::insert_statement::{
+    AsValueIterator, BatchInsert, DefaultValues, InsertableQueryfragment, IsValuesClause,
+};
 #[doc(inline)]
 pub use self::insert_statement::{
     IncompleteInsertStatement, InsertStatement, UndecoratedInsertRecord, ValuesClause,
@@ -49,7 +53,7 @@ pub use self::select_clause::{
     IntoBoxedSelectClause, SelectClauseExpression, SelectClauseQueryFragment,
 };
 #[doc(hidden)]
-pub use self::select_statement::{BoxedSelectStatement, SelectStatement};
+pub use self::select_statement::{BoxedSelectStatement, NoFromClause, SelectStatement};
 pub use self::sql_query::{BoxedSqlQuery, SqlQuery};
 #[doc(inline)]
 pub use self::update_statement::{
@@ -61,13 +65,21 @@ pub use self::limit_clause::{LimitClause, NoLimitClause};
 pub use self::limit_offset_clause::{BoxedLimitOffsetClause, LimitOffsetClause};
 pub use self::offset_clause::{NoOffsetClause, OffsetClause};
 
-pub(crate) use self::insert_statement::{BatchInsert, ColumnList};
+#[doc(hidden)]
+pub use self::returning_clause::ReturningClause;
+
+pub(crate) use self::insert_statement::ColumnList;
 
 use std::error::Error;
 
 use crate::backend::Backend;
 use crate::result::QueryResult;
 
+mod private {
+    #[allow(missing_debug_implementations, missing_copy_implementations)]
+    pub struct NotSpecialized;
+}
+
 #[doc(hidden)]
 pub type Binds = Vec<Option<Vec<u8>>>;
 /// A specialized Result type used with the query builder.
@@ -146,7 +158,7 @@ pub trait SelectQuery {
 ///
 /// [`ExecuteDsl`]: crate::query_dsl::methods::ExecuteDsl
 /// [`LoadQuery`]: crate::query_dsl::methods::LoadQuery
-pub trait QueryFragment<DB: Backend> {
+pub trait QueryFragment<DB: Backend, SP = self::private::NotSpecialized> {
     /// Walk over this `QueryFragment` for all passes.
     ///
     /// This method is where the actual behavior of an AST node is implemented.
diff --git a/diesel/src/query_builder/returning_clause.rs b/diesel/src/query_builder/returning_clause.rs
index a76d3d4e7b5b..2fbaca353523 100644
--- a/diesel/src/query_builder/returning_clause.rs
+++ b/diesel/src/query_builder/returning_clause.rs
@@ -1,8 +1,43 @@
-use crate::backend::SupportsReturningClause;
-
-simple_clause!(
-    NoReturningClause,
-    ReturningClause,
-    " RETURNING ",
-    backend_bounds = SupportsReturningClause
-);
+use super::{AstPass, QueryFragment};
+use crate::backend::Backend;
+use crate::query_builder::QueryId;
+use crate::result::QueryResult;
+
+#[derive(Debug, Clone, Copy, QueryId)]
+pub struct NoReturningClause;
+
+impl<DB: Backend> QueryFragment<DB> for NoReturningClause {
+    fn walk_ast(&self, _: AstPass<DB>) -> QueryResult<()> {
+        Ok(())
+    }
+}
+
+#[doc(hidden)]
+#[derive(Debug, Clone, Copy, QueryId)]
+pub struct ReturningClause<Expr>(pub Expr);
+
+impl<Expr, DB> QueryFragment<DB> for ReturningClause<Expr>
+where
+    DB: Backend,
+    Self: QueryFragment<DB, DB::ReturningClause>,
+{
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::ReturningClause>>::walk_ast(self, pass)
+    }
+}
+
+impl<Expr, DB>
+    QueryFragment<DB, crate::backend::sql_dialect::returning_clause::PgLikeReturningClause>
+    for ReturningClause<Expr>
+where
+    DB: Backend<
+        ReturningClause = crate::backend::sql_dialect::returning_clause::PgLikeReturningClause,
+    >,
+    Expr: QueryFragment<DB>,
+{
+    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
+        out.push_sql(" RETURNING ");
+        self.0.walk_ast(out.reborrow())?;
+        Ok(())
+    }
+}
diff --git a/diesel/src/query_builder/select_statement/boxed.rs b/diesel/src/query_builder/select_statement/boxed.rs
index d7a3c04f6829..197c776d8153 100644
--- a/diesel/src/query_builder/select_statement/boxed.rs
+++ b/diesel/src/query_builder/select_statement/boxed.rs
@@ -129,15 +129,17 @@ where
     }
 }
 
-impl<'a, ST, DB, GB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, (), DB, GB>
+impl<'a, ST, DB, GB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, NoFromClause, DB, GB>
 where
     DB: Backend,
+    NoFromClause: QueryFragment<DB, DB::EmptyFromClauseSyntax>,
     BoxedLimitOffsetClause<'a, DB>: QueryFragment<DB>,
 {
     fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
         out.push_sql("SELECT ");
         self.distinct.walk_ast(out.reborrow())?;
         self.select.walk_ast(out.reborrow())?;
+        self.from.walk_ast(out.reborrow())?;
         self.where_clause.walk_ast(out.reborrow())?;
         self.group_by.walk_ast(out.reborrow())?;
         self.having.walk_ast(out.reborrow())?;
diff --git a/diesel/src/query_builder/select_statement/mod.rs b/diesel/src/query_builder/select_statement/mod.rs
index 72c5c9e5289a..dd8a96b251d3 100644
--- a/diesel/src/query_builder/select_statement/mod.rs
+++ b/diesel/src/query_builder/select_statement/mod.rs
@@ -37,6 +37,19 @@ use crate::query_source::joins::{AppendSelection, Inner, Join};
 use crate::query_source::*;
 use crate::result::QueryResult;
 
+#[derive(Debug, Clone, Copy, QueryId)]
+pub struct NoFromClause;
+
+impl<DB> QueryFragment<DB, crate::backend::sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax>
+    for NoFromClause
+where
+    DB: Backend<EmptyFromClauseSyntax = crate::backend::sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax>,
+{
+    fn walk_ast(&self, _pass: AstPass<DB>) -> QueryResult<()> {
+        Ok(())
+    }
+}
+
 #[derive(Debug, Clone, Copy, QueryId)]
 #[doc(hidden)]
 #[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
@@ -158,10 +171,11 @@ where
 }
 
 impl<S, D, W, O, LOf, G, H, LC, DB> QueryFragment<DB>
-    for SelectStatement<(), S, D, W, O, LOf, G, H, LC>
+    for SelectStatement<NoFromClause, S, D, W, O, LOf, G, H, LC>
 where
     DB: Backend,
-    S: SelectClauseQueryFragment<(), DB>,
+    S: SelectClauseQueryFragment<NoFromClause, DB>,
+    NoFromClause: QueryFragment<DB, DB::EmptyFromClauseSyntax>,
     D: QueryFragment<DB>,
     W: QueryFragment<DB>,
     O: QueryFragment<DB>,
@@ -173,7 +187,8 @@ where
     fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
         out.push_sql("SELECT ");
         self.distinct.walk_ast(out.reborrow())?;
-        self.select.walk_ast(&(), out.reborrow())?;
+        self.select.walk_ast(&NoFromClause, out.reborrow())?;
+        self.from.walk_ast(out.reborrow())?;
         self.where_clause.walk_ast(out.reborrow())?;
         self.group_by.walk_ast(out.reborrow())?;
         self.having.walk_ast(out.reborrow())?;
diff --git a/diesel/src/query_builder/upsert/on_conflict_actions.rs b/diesel/src/query_builder/upsert/on_conflict_actions.rs
index 0b408f59b422..d1e2771603dd 100644
--- a/diesel/src/query_builder/upsert/on_conflict_actions.rs
+++ b/diesel/src/query_builder/upsert/on_conflict_actions.rs
@@ -1,4 +1,4 @@
-use crate::backend::{Backend, SupportsOnConflictClause};
+use crate::backend::{sql_dialect, Backend};
 use crate::expression::{AppearsOnTable, Expression};
 use crate::query_builder::*;
 use crate::query_source::*;
@@ -10,7 +10,18 @@ pub struct DoNothing;
 
 impl<DB> QueryFragment<DB> for DoNothing
 where
-    DB: Backend + SupportsOnConflictClause,
+    DB: Backend,
+    Self: QueryFragment<DB, DB::OnConflictClause>,
+{
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::OnConflictClause>>::walk_ast(self, pass)
+    }
+}
+
+impl<DB, T> QueryFragment<DB, T> for DoNothing
+where
+    DB: Backend,
+    T: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
 {
     fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
         out.push_sql(" DO NOTHING");
@@ -32,7 +43,18 @@ impl<T> DoUpdate<T> {
 
 impl<DB, T> QueryFragment<DB> for DoUpdate<T>
 where
-    DB: Backend + SupportsOnConflictClause,
+    DB: Backend,
+    Self: QueryFragment<DB, DB::OnConflictClause>,
+{
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::OnConflictClause>>::walk_ast(self, pass)
+    }
+}
+
+impl<DB, T, SP> QueryFragment<DB, SP> for DoUpdate<T>
+where
+    DB: Backend,
+    SP: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
     T: QueryFragment<DB>,
 {
     fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
@@ -59,7 +81,18 @@ impl<T> Excluded<T> {
 
 impl<DB, T> QueryFragment<DB> for Excluded<T>
 where
-    DB: Backend + SupportsOnConflictClause,
+    DB: Backend,
+    Self: QueryFragment<DB, DB::OnConflictClause>,
+{
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::OnConflictClause>>::walk_ast(self, pass)
+    }
+}
+
+impl<DB, T, SP> QueryFragment<DB, SP> for Excluded<T>
+where
+    DB: Backend,
+    SP: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
     T: Column,
 {
     fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
diff --git a/diesel/src/query_builder/upsert/on_conflict_clause.rs b/diesel/src/query_builder/upsert/on_conflict_clause.rs
index 1f4a5c90a947..d1c44a055f90 100644
--- a/diesel/src/query_builder/upsert/on_conflict_clause.rs
+++ b/diesel/src/query_builder/upsert/on_conflict_clause.rs
@@ -1,6 +1,7 @@
 use super::on_conflict_actions::*;
 use super::on_conflict_target::*;
-use crate::backend::{Backend, SupportsOnConflictClause};
+use crate::backend::sql_dialect;
+use crate::backend::Backend;
 use crate::insertable::*;
 use crate::query_builder::*;
 use crate::result::QueryResult;
@@ -38,7 +39,8 @@ impl<Values, Target, Action> OnConflictValues<Values, Target, Action> {
 impl<DB, Values, Target, Action> CanInsertInSingleQuery<DB>
     for OnConflictValues<Values, Target, Action>
 where
-    DB: Backend + SupportsOnConflictClause,
+    DB: Backend,
+    DB::OnConflictClause: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
     Values: CanInsertInSingleQuery<DB>,
 {
     fn rows_to_insert(&self) -> Option<usize> {
@@ -48,7 +50,8 @@ where
 
 impl<DB, Values, Target, Action> QueryFragment<DB> for OnConflictValues<Values, Target, Action>
 where
-    DB: Backend + SupportsOnConflictClause,
+    DB: Backend,
+    DB::OnConflictClause: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
     Values: QueryFragment<DB>,
     Target: QueryFragment<DB>,
     Action: QueryFragment<DB>,
diff --git a/diesel/src/query_builder/upsert/on_conflict_target.rs b/diesel/src/query_builder/upsert/on_conflict_target.rs
index a9b1be0dd304..651a9e9ed8b0 100644
--- a/diesel/src/query_builder/upsert/on_conflict_target.rs
+++ b/diesel/src/query_builder/upsert/on_conflict_target.rs
@@ -1,4 +1,4 @@
-use crate::backend::{Backend, SupportsOnConflictClause};
+use crate::backend::{sql_dialect, Backend};
 use crate::expression::SqlLiteral;
 use crate::query_builder::*;
 use crate::query_source::Column;
@@ -13,7 +13,8 @@ pub struct NoConflictTarget;
 
 impl<DB> QueryFragment<DB> for NoConflictTarget
 where
-    DB: Backend + SupportsOnConflictClause,
+    DB: Backend,
+    DB::OnConflictClause: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
 {
     fn walk_ast(&self, _: AstPass<DB>) -> QueryResult<()> {
         Ok(())
@@ -28,7 +29,18 @@ pub struct ConflictTarget<T>(pub T);
 
 impl<DB, T> QueryFragment<DB> for ConflictTarget<T>
 where
-    DB: Backend + SupportsOnConflictClause,
+    DB: Backend,
+    Self: QueryFragment<DB, DB::OnConflictClause>,
+{
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::OnConflictClause>>::walk_ast(self, pass)
+    }
+}
+
+impl<DB, T, SP> QueryFragment<DB, SP> for ConflictTarget<T>
+where
+    DB: Backend<OnConflictClause = SP>,
+    SP: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
     T: Column,
 {
     fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
@@ -41,9 +53,10 @@ where
 
 impl<T> OnConflictTarget<T::Table> for ConflictTarget<T> where T: Column {}
 
-impl<DB, ST> QueryFragment<DB> for ConflictTarget<SqlLiteral<ST>>
+impl<DB, ST, SP> QueryFragment<DB, SP> for ConflictTarget<SqlLiteral<ST>>
 where
-    DB: Backend + SupportsOnConflictClause,
+    DB: Backend<OnConflictClause = SP>,
+    SP: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
     SqlLiteral<ST>: QueryFragment<DB>,
 {
     fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
@@ -55,9 +68,10 @@ where
 
 impl<Tab, ST> OnConflictTarget<Tab> for ConflictTarget<SqlLiteral<ST>> {}
 
-impl<DB, T> QueryFragment<DB> for ConflictTarget<(T,)>
+impl<DB, T, SP> QueryFragment<DB, SP> for ConflictTarget<(T,)>
 where
-    DB: Backend + SupportsOnConflictClause,
+    DB: Backend<OnConflictClause = SP>,
+    SP: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
     T: Column,
 {
     fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
@@ -77,8 +91,9 @@ macro_rules! on_conflict_tuples {
         }
     )+) => {
         $(
-            impl<_DB, _T, $($T),*> QueryFragment<_DB> for ConflictTarget<(_T, $($T),*)> where
-                _DB: Backend + SupportsOnConflictClause,
+            impl<_DB, _T, _SP, $($T),*> QueryFragment<_DB, _SP> for ConflictTarget<(_T, $($T),*)> where
+                _DB: Backend<OnConflictClause = _SP>,
+                _SP: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
                 _T: Column,
                 $($T: Column<Table=_T::Table>,)*
             {
diff --git a/diesel/src/query_builder/upsert/on_conflict_target_decorations.rs b/diesel/src/query_builder/upsert/on_conflict_target_decorations.rs
index a510723eefe5..3c34b58f3756 100644
--- a/diesel/src/query_builder/upsert/on_conflict_target_decorations.rs
+++ b/diesel/src/query_builder/upsert/on_conflict_target_decorations.rs
@@ -1,4 +1,4 @@
-use crate::backend::{Backend, SupportsOnConflictClause, SupportsOnConflictTargetDecorations};
+use crate::backend::Backend;
 use crate::expression::Expression;
 use crate::query_builder::upsert::on_conflict_target::{ConflictTarget, NoConflictTarget};
 use crate::query_builder::where_clause::{NoWhereClause, WhereAnd, WhereClause};
@@ -21,8 +21,8 @@ pub trait DecoratableTarget<P> {
 
 #[derive(Debug)]
 pub struct DecoratedConflictTarget<T, U> {
-    target: T,
-    where_clause: U,
+    pub(crate) target: T,
+    pub(crate) where_clause: U,
 }
 
 impl<T, P> DecoratableTarget<P> for T
@@ -59,13 +59,10 @@ where
 
 impl<DB, T, U> QueryFragment<DB> for DecoratedConflictTarget<T, U>
 where
-    T: QueryFragment<DB>,
-    U: QueryFragment<DB>,
-    DB: Backend + SupportsOnConflictClause + SupportsOnConflictTargetDecorations,
+    DB: Backend,
+    Self: QueryFragment<DB, DB::OnConflictClause>,
 {
-    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
-        self.target.walk_ast(out.reborrow())?;
-        self.where_clause.walk_ast(out.reborrow())?;
-        Ok(())
+    fn walk_ast(&self, pass: AstPass<DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::OnConflictClause>>::walk_ast(self, pass)
     }
 }
diff --git a/diesel/src/sqlite/backend.rs b/diesel/src/sqlite/backend.rs
index bb7451cffa28..66724a0e46d2 100644
--- a/diesel/src/sqlite/backend.rs
+++ b/diesel/src/sqlite/backend.rs
@@ -53,5 +53,25 @@ impl TypeMetadata for Sqlite {
     type MetadataLookup = ();
 }
 
-impl SupportsOnConflictClause for Sqlite {}
-impl UsesAnsiSavepointSyntax for Sqlite {}
+impl SqlDialect for Sqlite {
+    type ReturningClause = sql_dialect::returning_clause::DoesNotSupportReturningClause;
+
+    type OnConflictClause = SqliteOnConflictClaues;
+
+    type InsertWithDefaultKeyword =
+        sql_dialect::default_keyword_for_insert::DoesNotSupportDefaultKeyword;
+    type BatchInsertSupport = SqliteBatchInsert;
+    type DefaultValueClauseForInsert = sql_dialect::default_value_clause::AnsiDefaultValueClause;
+
+    type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax;
+    type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax;
+    type ArrayComparision = sql_dialect::array_comparision::AnsiSqlArrayComparison;
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct SqliteOnConflictClaues;
+
+impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for SqliteOnConflictClaues {}
+
+#[derive(Debug, Copy, Clone)]
+pub struct SqliteBatchInsert;
diff --git a/diesel/src/sqlite/mod.rs b/diesel/src/sqlite/mod.rs
index 9193568b5604..c2840bd55783 100644
--- a/diesel/src/sqlite/mod.rs
+++ b/diesel/src/sqlite/mod.rs
@@ -4,7 +4,7 @@
 //! However, if you are writing code specifically to extend Diesel on
 //! SQLite, you may need to work with this module directly.
 
-mod backend;
+pub(crate) mod backend;
 mod connection;
 pub(crate) mod expression;
 mod types;
diff --git a/diesel/src/type_impls/primitives.rs b/diesel/src/type_impls/primitives.rs
index 29cb4c09e02d..77392113ab9a 100644
--- a/diesel/src/type_impls/primitives.rs
+++ b/diesel/src/type_impls/primitives.rs
@@ -121,7 +121,6 @@ where
 /// impl in terms of `String`, but don't want to allocate. We have to return a
 /// raw pointer instead of a reference with a lifetime due to the structure of
 /// `FromSql`
-#[cfg(not(feature = "unstable"))]
 impl<DB> FromSql<sql_types::Text, DB> for *const str
 where
     DB: Backend + for<'a> BinaryRawValue<'a>,
@@ -133,18 +132,6 @@ where
     }
 }
 
-#[cfg(feature = "unstable")]
-impl<DB> FromSql<sql_types::Text, DB> for *const str
-where
-    DB: Backend + for<'a> BinaryRawValue<'a>,
-{
-    default fn from_sql(value: crate::backend::RawValue<DB>) -> deserialize::Result<Self> {
-        use std::str;
-        let string = str::from_utf8(DB::as_bytes(value))?;
-        Ok(string as *const _)
-    }
-}
-
 impl<DB: Backend> ToSql<sql_types::Text, DB> for str {
     fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> serialize::Result {
         out.write_all(self.as_bytes())
diff --git a/diesel/src/type_impls/tuples.rs b/diesel/src/type_impls/tuples.rs
index b5e1bea00cf9..27ff56981bff 100644
--- a/diesel/src/type_impls/tuples.rs
+++ b/diesel/src/type_impls/tuples.rs
@@ -8,7 +8,7 @@ use crate::expression::{
     IsContainedInGroupBy, QueryMetadata, Selectable, SelectableExpression, TypedExpressionType,
     ValidGrouping,
 };
-use crate::insertable::{CanInsertInSingleQuery, InsertValues, Insertable};
+use crate::insertable::{CanInsertInSingleQuery, InsertValues, Insertable, InsertableOptionHelper};
 use crate::query_builder::*;
 use crate::query_dsl::load_dsl::CompatibleType;
 use crate::query_source::*;
@@ -183,6 +183,18 @@ macro_rules! tuple_impls {
                 }
             }
 
+            impl<__T, $($ST,)* Tab> Insertable<Tab> for InsertableOptionHelper<__T, ($($ST,)*)>
+            where
+                __T: Insertable<Tab>,
+                __T::Values: Default,
+            {
+                type Values = __T::Values;
+
+                fn values(self) -> Self::Values {
+                    self.0.map(|v| v.values()).unwrap_or_default()
+                }
+            }
+
             impl<$($T,)+ QS> SelectableExpression<QS> for ($($T,)+) where
                 $($T: SelectableExpression<QS>,)+
                 ($($T,)+): AppearsOnTable<QS>,


Test patch:
diff --git a/diesel_compile_tests/Cargo.toml b/diesel_compile_tests/Cargo.toml
index c25dffe1a14c..d084de0a7a02 100644
--- a/diesel_compile_tests/Cargo.toml
+++ b/diesel_compile_tests/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 authors = ["Sean Griffin <sean@seantheprogrammer.com>"]
 
 [dependencies]
-diesel = { version = "2.0.0", default-features = false, features = ["extras", "sqlite", "postgres", "mysql", "unstable"], path = "../diesel" }
+diesel = { version = "2.0.0", default-features = false, features = ["extras", "sqlite", "postgres", "mysql", "unstable", "with-deprecated"], path = "../diesel" }
 trybuild = "1.0.41"
 
 [workspace]
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 62c3eb171427..2eea89b58533 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
@@ -1,3 +1,11 @@
+warning: use of deprecated function `diesel::dsl::any`: Use `ExpressionMethods::eq_any` instead
+  --> $DIR/any_is_only_selectable_if_inner_expr_is_selectable.rs:30:34
+   |
+30 |     let _ = stuff.filter(name.eq(any(more_stuff::names)))
+   |                                  ^^^
+   |
+   = note: `#[warn(deprecated)]` on by default
+
 error[E0277]: the trait bound `stuff::table: AppearsInFromClause<more_stuff::table>` is not satisfied
   --> $DIR/any_is_only_selectable_if_inner_expr_is_selectable.rs:31:10
    |
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 927edf363d1a..9de7857ab514 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
@@ -1,18 +1,18 @@
-error[E0277]: the trait bound `f64: SelectableExpression<()>` is not satisfied
+error[E0277]: the trait bound `f64: SelectableExpression<NoFromClause>` is not satisfied
    --> $DIR/array_expressions_must_be_correct_type.rs:9:5
     |
 9   |     select(array((1f64, 3f64))).get_result::<Vec<i32>>(&mut connection);
-    |     ^^^^^^ the trait `SelectableExpression<()>` is not implemented for `f64`
+    |     ^^^^^^ the trait `SelectableExpression<NoFromClause>` is not implemented for `f64`
     |
    ::: $DIESEL/src/query_builder/functions.rs
     |
-    |     SelectStatement<()>: SelectDsl<T>,
-    |                          ------------ required by this bound in `diesel::select`
+    |     SelectStatement<crate::query_builder::select_statement::NoFromClause>: SelectDsl<T>,
+    |                                                                            ------------ required by this bound in `diesel::select`
     |
-    = note: required because of the requirements on the impl of `SelectableExpression<()>` for `(f64, f64)`
+    = 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<()>` for `diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>`
-    = note: required because of the requirements on the impl of `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>` for `SelectStatement<()>`
+    = 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 `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>` for `SelectStatement<NoFromClause>`
 
 error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
    --> $DIR/array_expressions_must_be_correct_type.rs:9:5
@@ -22,26 +22,26 @@ error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
     |
    ::: $DIESEL/src/query_builder/functions.rs
     |
-    |     SelectStatement<()>: SelectDsl<T>,
-    |                          ------------ required by this bound in `diesel::select`
+    |     SelectStatement<crate::query_builder::select_statement::NoFromClause>: SelectDsl<T>,
+    |                                                                            ------------ 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 `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>` for `SelectStatement<()>`
+    = note: required because of the requirements on the impl of `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>` for `SelectStatement<NoFromClause>`
 
-error[E0277]: the trait bound `f64: SelectableExpression<()>` is not satisfied
+error[E0277]: the trait bound `f64: SelectableExpression<NoFromClause>` is not satisfied
  --> $DIR/array_expressions_must_be_correct_type.rs:9:33
   |
 9 |     select(array((1f64, 3f64))).get_result::<Vec<i32>>(&mut connection);
-  |                                 ^^^^^^^^^^ the trait `SelectableExpression<()>` is not implemented for `f64`
+  |                                 ^^^^^^^^^^ the trait `SelectableExpression<NoFromClause>` is not implemented for `f64`
   |
-  = note: required because of the requirements on the impl of `SelectableExpression<()>` for `(f64, f64)`
+  = 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<()>` for `diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>`
-  = note: required because of the requirements on the impl of `SelectClauseExpression<()>` 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<(), 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 `LoadQuery<_, Vec<i32>>` for `SelectStatement<(), 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 `SelectableExpression<NoFromClause>` for `diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>`
+  = note: required because of the requirements on the impl of `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 `LoadQuery<_, Vec<i32>>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>>`
 
 error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
  --> $DIR/array_expressions_must_be_correct_type.rs:9:33
@@ -52,8 +52,8 @@ error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
   = 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<(), 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 `LoadQuery<_, Vec<i32>>` for `SelectStatement<(), 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 `LoadQuery<_, Vec<i32>>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>>`
 
 error[E0277]: the trait bound `f64: QueryId` is not satisfied
  --> $DIR/array_expressions_must_be_correct_type.rs:9:33
@@ -63,8 +63,8 @@ error[E0277]: the trait bound `f64: QueryId` is not satisfied
   |
   = note: required because of the requirements on the impl of `QueryId` for `(f64, f64)`
   = note: 3 redundant requirements hidden
-  = note: required because of the requirements on the impl of `QueryId` for `SelectStatement<(), 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 `LoadQuery<_, Vec<i32>>` for `SelectStatement<(), 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 `QueryId` 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 `LoadQuery<_, Vec<i32>>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>>`
 
 error[E0277]: the trait bound `f64: QueryFragment<Pg>` is not satisfied
  --> $DIR/array_expressions_must_be_correct_type.rs:9:33
@@ -75,10 +75,10 @@ error[E0277]: the trait bound `f64: QueryFragment<Pg>` is not satisfied
   = note: required because of the requirements on the impl of `QueryFragment<Pg>` for `(f64, f64)`
   = note: 2 redundant requirements hidden
   = note: required because of the requirements on the impl of `QueryFragment<Pg>` for `diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>`
-  = note: required because of the requirements on the impl of `SelectClauseQueryFragment<(), Pg>` 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 `SelectClauseQueryFragment<NoFromClause, Pg>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>`
   = note: 1 redundant requirements hidden
-  = note: required because of the requirements on the impl of `QueryFragment<Pg>` for `SelectStatement<(), 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 `LoadQuery<_, Vec<i32>>` for `SelectStatement<(), 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 `QueryFragment<Pg>` 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 `LoadQuery<_, Vec<i32>>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>>`
 
 error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied
   --> $DIR/array_expressions_must_be_correct_type.rs:9:12
@@ -94,11 +94,11 @@ error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied
    = 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)`
 
-error[E0277]: the trait bound `SelectStatement<()>: SelectDsl<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>` is not satisfied
+error[E0277]: the trait bound `SelectStatement<NoFromClause>: SelectDsl<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>` is not satisfied
  --> $DIR/array_expressions_must_be_correct_type.rs:9:5
   |
 9 |     select(array((1f64, 3f64))).get_result::<Vec<i32>>(&mut connection);
-  |     ^^^^^^ the trait `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>` is not implemented for `SelectStatement<()>`
+  |     ^^^^^^ the trait `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(f64, f64), diesel::sql_types::Integer>>` is not implemented for `SelectStatement<NoFromClause>`
   |
   = help: the following implementations were found:
             <SelectStatement<F, S, D, W, O, LOf, G, H, LC> as SelectDsl<Selection>>
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 6a9335579ad8..9b47e48972c5 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
@@ -1,18 +1,18 @@
-error[E0277]: the trait bound `f64: SelectableExpression<()>` is not satisfied
+error[E0277]: the trait bound `f64: SelectableExpression<NoFromClause>` is not satisfied
    --> $DIR/array_expressions_must_be_same_type.rs:11:5
     |
 11  |     select(array((1, 3f64))).get_result::<Vec<i32>>(&mut connection).unwrap();
-    |     ^^^^^^ the trait `SelectableExpression<()>` is not implemented for `f64`
+    |     ^^^^^^ the trait `SelectableExpression<NoFromClause>` is not implemented for `f64`
     |
    ::: $DIESEL/src/query_builder/functions.rs
     |
-    |     SelectStatement<()>: SelectDsl<T>,
-    |                          ------------ required by this bound in `diesel::select`
+    |     SelectStatement<crate::query_builder::select_statement::NoFromClause>: SelectDsl<T>,
+    |                                                                            ------------ required by this bound in `diesel::select`
     |
-    = note: required because of the requirements on the impl of `SelectableExpression<()>` for `(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64)`
+    = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64)`
     = note: 1 redundant requirements hidden
-    = note: required because of the requirements on the impl of `SelectableExpression<()>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>`
-    = note: required because of the requirements on the impl of `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>` for `SelectStatement<()>`
+    = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>`
+    = note: required because of the requirements on the impl of `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>` for `SelectStatement<NoFromClause>`
 
 error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
    --> $DIR/array_expressions_must_be_same_type.rs:11:5
@@ -22,26 +22,26 @@ error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
     |
    ::: $DIESEL/src/query_builder/functions.rs
     |
-    |     SelectStatement<()>: SelectDsl<T>,
-    |                          ------------ required by this bound in `diesel::select`
+    |     SelectStatement<crate::query_builder::select_statement::NoFromClause>: SelectDsl<T>,
+    |                                                                            ------------ required by this bound in `diesel::select`
     |
     = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64)`
     = note: 1 redundant requirements hidden
     = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>`
-    = note: required because of the requirements on the impl of `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>` for `SelectStatement<()>`
+    = note: required because of the requirements on the impl of `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>` for `SelectStatement<NoFromClause>`
 
-error[E0277]: the trait bound `f64: SelectableExpression<()>` is not satisfied
+error[E0277]: the trait bound `f64: SelectableExpression<NoFromClause>` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:11:30
    |
 11 |     select(array((1, 3f64))).get_result::<Vec<i32>>(&mut connection).unwrap();
-   |                              ^^^^^^^^^^ the trait `SelectableExpression<()>` is not implemented for `f64`
+   |                              ^^^^^^^^^^ the trait `SelectableExpression<NoFromClause>` is not implemented for `f64`
    |
-   = note: required because of the requirements on the impl of `SelectableExpression<()>` for `(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64)`
+   = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64)`
    = note: 1 redundant requirements hidden
-   = note: required because of the requirements on the impl of `SelectableExpression<()>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>`
-   = note: required because of the requirements on the impl of `SelectClauseExpression<()>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>`
-   = note: required because of the requirements on the impl of `Query` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::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<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
+   = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>`
+   = note: required because of the requirements on the impl of `SelectClauseExpression<NoFromClause>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::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::expression::bound::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::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
 
 error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:11:30
@@ -52,8 +52,8 @@ error[E0277]: the trait bound `f64: ValidGrouping<()>` is not satisfied
    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64)`
    = note: 1 redundant requirements hidden
    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>`
-   = note: required because of the requirements on the impl of `Query` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::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<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::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::expression::bound::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::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
 
 error[E0277]: the trait bound `f64: QueryId` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:11:30
@@ -63,8 +63,8 @@ error[E0277]: the trait bound `f64: QueryId` is not satisfied
    |
    = note: required because of the requirements on the impl of `QueryId` for `(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64)`
    = note: 3 redundant requirements hidden
-   = note: required because of the requirements on the impl of `QueryId` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::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<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
+   = 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<(diesel::expression::bound::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::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
 
 error[E0277]: the trait bound `f64: QueryFragment<Pg>` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:11:30
@@ -75,10 +75,10 @@ error[E0277]: the trait bound `f64: QueryFragment<Pg>` is not satisfied
    = note: required because of the requirements on the impl of `QueryFragment<Pg>` for `(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64)`
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `QueryFragment<Pg>` for `diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>`
-   = note: required because of the requirements on the impl of `SelectClauseQueryFragment<(), Pg>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>`
+   = note: required because of the requirements on the impl of `SelectClauseQueryFragment<NoFromClause, Pg>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>`
    = note: 1 redundant requirements hidden
-   = note: required because of the requirements on the impl of `QueryFragment<Pg>` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::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<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
+   = 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<(diesel::expression::bound::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::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>>`
 
 error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:11:12
@@ -94,16 +94,16 @@ error[E0277]: the trait bound `f64: diesel::Expression` is not satisfied
    = 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)`
 
-error[E0277]: the trait bound `{integer}: SelectableExpression<()>` is not satisfied
+error[E0277]: the trait bound `{integer}: SelectableExpression<NoFromClause>` is not satisfied
    --> $DIR/array_expressions_must_be_same_type.rs:12:5
     |
 12  |     select(array((1, 3f64))).get_result::<Vec<f64>>(&mut connection).unwrap();
-    |     ^^^^^^ the trait `SelectableExpression<()>` is not implemented for `{integer}`
+    |     ^^^^^^ the trait `SelectableExpression<NoFromClause>` is not implemented for `{integer}`
     |
    ::: $DIESEL/src/query_builder/functions.rs
     |
-    |     SelectStatement<()>: SelectDsl<T>,
-    |                          ------------ required by this bound in `diesel::select`
+    |     SelectStatement<crate::query_builder::select_statement::NoFromClause>: SelectDsl<T>,
+    |                                                                            ------------ required by this bound in `diesel::select`
     |
     = help: the following implementations were found:
               <&'a T as SelectableExpression<QS>>
@@ -111,10 +111,10 @@ error[E0277]: the trait bound `{integer}: SelectableExpression<()>` is not satis
               <(A, B, C) as SelectableExpression<QS>>
               <(A, B, C, D) as SelectableExpression<QS>>
             and 131 others
-    = note: required because of the requirements on the impl of `SelectableExpression<()>` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
+    = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
     = note: 1 redundant requirements hidden
-    = note: required because of the requirements on the impl of `SelectableExpression<()>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
-    = note: required because of the requirements on the impl of `SelectDsl<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>` for `SelectStatement<()>`
+    = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
+    = note: required because of the requirements on the impl of `SelectDsl<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>` for `SelectStatement<NoFromClause>`
 
 error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
    --> $DIR/array_expressions_must_be_same_type.rs:12:5
@@ -124,8 +124,8 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
     |
    ::: $DIESEL/src/query_builder/functions.rs
     |
-    |     SelectStatement<()>: SelectDsl<T>,
-    |                          ------------ required by this bound in `diesel::select`
+    |     SelectStatement<crate::query_builder::select_statement::NoFromClause>: SelectDsl<T>,
+    |                                                                            ------------ required by this bound in `diesel::select`
     |
     = help: the following implementations were found:
               <&'a T as ValidGrouping<GB>>
@@ -136,13 +136,13 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
     = note: required because of the requirements on the impl of `ValidGrouping<()>` for `({integer}, diesel::expression::bound::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::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
-    = note: required because of the requirements on the impl of `SelectDsl<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>` for `SelectStatement<()>`
+    = note: required because of the requirements on the impl of `SelectDsl<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>` for `SelectStatement<NoFromClause>`
 
-error[E0277]: the trait bound `{integer}: SelectableExpression<()>` is not satisfied
+error[E0277]: the trait bound `{integer}: SelectableExpression<NoFromClause>` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:12:30
    |
 12 |     select(array((1, 3f64))).get_result::<Vec<f64>>(&mut connection).unwrap();
-   |                              ^^^^^^^^^^ the trait `SelectableExpression<()>` is not implemented for `{integer}`
+   |                              ^^^^^^^^^^ the trait `SelectableExpression<NoFromClause>` is not implemented for `{integer}`
    |
    = help: the following implementations were found:
              <&'a T as SelectableExpression<QS>>
@@ -150,12 +150,12 @@ error[E0277]: the trait bound `{integer}: SelectableExpression<()>` is not satis
              <(A, B, C) as SelectableExpression<QS>>
              <(A, B, C, D) as SelectableExpression<QS>>
            and 131 others
-   = note: required because of the requirements on the impl of `SelectableExpression<()>` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
+   = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
    = note: 1 redundant requirements hidden
-   = note: required because of the requirements on the impl of `SelectableExpression<()>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
-   = note: required because of the requirements on the impl of `SelectClauseExpression<()>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>`
-   = note: required because of the requirements on the impl of `Query` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
-   = note: required because of the requirements on the impl of `LoadQuery<_, Vec<f64>>` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
+   = note: required because of the requirements on the impl of `SelectableExpression<NoFromClause>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
+   = note: required because of the requirements on the impl of `SelectClauseExpression<NoFromClause>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::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::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
+   = note: required because of the requirements on the impl of `LoadQuery<_, Vec<f64>>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
 
 error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:12:30
@@ -172,8 +172,8 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied
    = note: required because of the requirements on the impl of `ValidGrouping<()>` for `({integer}, diesel::expression::bound::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::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
-   = note: required because of the requirements on the impl of `Query` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
-   = note: required because of the requirements on the impl of `LoadQuery<_, Vec<f64>>` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::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::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
+   = note: required because of the requirements on the impl of `LoadQuery<_, Vec<f64>>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
 
 error[E0277]: the trait bound `{integer}: QueryId` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:12:30
@@ -186,11 +186,11 @@ error[E0277]: the trait bound `{integer}: QueryId` is not satisfied
              <() as QueryId>
              <(A, B) as QueryId>
              <(A, B, C) as QueryId>
-           and 208 others
+           and 210 others
    = note: required because of the requirements on the impl of `QueryId` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
    = note: 3 redundant requirements hidden
-   = note: required because of the requirements on the impl of `QueryId` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
-   = note: required because of the requirements on the impl of `LoadQuery<_, Vec<f64>>` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
+   = 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::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
+   = note: required because of the requirements on the impl of `LoadQuery<_, Vec<f64>>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
 
 error[E0277]: the trait bound `{integer}: QueryFragment<Pg>` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:12:30
@@ -203,14 +203,14 @@ error[E0277]: the trait bound `{integer}: QueryFragment<Pg>` is not satisfied
              <() as QueryFragment<DB>>
              <(A, B) as QueryFragment<__DB>>
              <(A, B, C) as QueryFragment<__DB>>
-           and 223 others
+           and 242 others
    = note: required because of the requirements on the impl of `QueryFragment<Pg>` for `({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>)`
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `QueryFragment<Pg>` for `diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>`
-   = note: required because of the requirements on the impl of `SelectClauseQueryFragment<(), Pg>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>`
+   = note: required because of the requirements on the impl of `SelectClauseQueryFragment<NoFromClause, Pg>` for `diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>`
    = note: 1 redundant requirements hidden
-   = note: required because of the requirements on the impl of `QueryFragment<Pg>` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
-   = note: required because of the requirements on the impl of `LoadQuery<_, Vec<f64>>` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
+   = 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::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
+   = note: required because of the requirements on the impl of `LoadQuery<_, Vec<f64>>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>>`
 
 error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:12:12
@@ -232,20 +232,20 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied
    = 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)`
 
-error[E0277]: the trait bound `SelectStatement<()>: SelectDsl<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>` is not satisfied
+error[E0277]: the trait bound `SelectStatement<NoFromClause>: SelectDsl<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:11:5
    |
 11 |     select(array((1, 3f64))).get_result::<Vec<i32>>(&mut connection).unwrap();
-   |     ^^^^^^ the trait `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>` is not implemented for `SelectStatement<()>`
+   |     ^^^^^^ the trait `SelectDsl<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>, f64), diesel::sql_types::Integer>>` is not implemented for `SelectStatement<NoFromClause>`
    |
    = help: the following implementations were found:
              <SelectStatement<F, S, D, W, O, LOf, G, H, LC> as SelectDsl<Selection>>
 
-error[E0277]: the trait bound `SelectStatement<()>: SelectDsl<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>` is not satisfied
+error[E0277]: the trait bound `SelectStatement<NoFromClause>: SelectDsl<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>` is not satisfied
   --> $DIR/array_expressions_must_be_same_type.rs:12:5
    |
 12 |     select(array((1, 3f64))).get_result::<Vec<f64>>(&mut connection).unwrap();
-   |     ^^^^^^ the trait `SelectDsl<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>` is not implemented for `SelectStatement<()>`
+   |     ^^^^^^ the trait `SelectDsl<diesel::pg::expression::array::ArrayLiteral<({integer}, diesel::expression::bound::Bound<diesel::sql_types::Double, f64>), diesel::sql_types::Double>>` is not implemented for `SelectStatement<NoFromClause>`
    |
    = help: the following implementations were found:
              <SelectStatement<F, S, D, W, O, LOf, G, H, LC> as SelectDsl<Selection>>
diff --git a/diesel_compile_tests/tests/fail/array_only_usable_with_pg.stderr b/diesel_compile_tests/tests/fail/array_only_usable_with_pg.stderr
index 309e78588330..96c598114085 100644
--- a/diesel_compile_tests/tests/fail/array_only_usable_with_pg.stderr
+++ b/diesel_compile_tests/tests/fail/array_only_usable_with_pg.stderr
@@ -4,7 +4,7 @@ error[E0271]: type mismatch resolving `<diesel::SqliteConnection as diesel::Conn
 8 |     select(array((1,))).get_result::<Vec<i32>>(&mut connection);
   |                         ^^^^^^^^^^ expected struct `Sqlite`, found struct `Pg`
   |
-  = note: required because of the requirements on the impl of `LoadQuery<diesel::SqliteConnection, Vec<i32>>` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>,), diesel::sql_types::Integer>>>`
+  = note: required because of the requirements on the impl of `LoadQuery<diesel::SqliteConnection, Vec<i32>>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>,), diesel::sql_types::Integer>>>`
 
 error[E0271]: type mismatch resolving `<diesel::MysqlConnection as diesel::Connection>::Backend == Pg`
   --> $DIR/array_only_usable_with_pg.rs:11:25
@@ -12,4 +12,4 @@ error[E0271]: type mismatch resolving `<diesel::MysqlConnection as diesel::Conne
 11 |     select(array((1,))).get_result::<Vec<i32>>(&mut connection);
    |                         ^^^^^^^^^^ expected struct `Mysql`, found struct `Pg`
    |
-   = note: required because of the requirements on the impl of `LoadQuery<diesel::MysqlConnection, Vec<i32>>` for `SelectStatement<(), diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>,), diesel::sql_types::Integer>>>`
+   = note: required because of the requirements on the impl of `LoadQuery<diesel::MysqlConnection, Vec<i32>>` for `SelectStatement<NoFromClause, diesel::query_builder::select_clause::SelectClause<diesel::pg::expression::array::ArrayLiteral<(diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>,), diesel::sql_types::Integer>>>`
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 7abf1e87494c..d1c9bacc5031 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
@@ -1,12 +1,12 @@
-error[E0271]: type mismatch resolving `<() as AppearsInFromClause<users::table>>::Count == diesel::query_source::Once`
+error[E0271]: type mismatch resolving `<NoFromClause as AppearsInFromClause<users::table>>::Count == diesel::query_source::Once`
   --> $DIR/columns_cannot_be_rhs_of_insert.rs:20:10
    |
 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<()>` for `columns::hair_color`
+   = note: required because of the requirements on the impl of `AppearsOnTable<NoFromClause>` for `columns::hair_color`
    = note: 1 redundant requirements hidden
-   = note: required because of the requirements on the impl of `AppearsOnTable<()>` for `&columns::hair_color`
+   = 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>`
    = note: required because of the requirements on the impl of `QueryFragment<_>` for `ValuesClause<ColumnInsertValue<columns::name, &columns::hair_color>, users::table>`
    = note: 1 redundant requirements hidden
diff --git a/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.stderr b/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.stderr
index 6db0e39fa2ab..98fd853b35fa 100644
--- a/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.stderr
+++ b/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.stderr
@@ -7,7 +7,7 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::Yes: MixedAggre
    = help: the following implementations were found:
              <diesel::expression::is_aggregate::Yes as MixedAggregates<diesel::expression::is_aggregate::Never>>
              <diesel::expression::is_aggregate::Yes as MixedAggregates<diesel::expression::is_aggregate::Yes>>
-   = note: required because of the requirements on the impl of `Query` for `UpdateStatement<users::table, diesel::query_builder::where_clause::WhereClause<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<count::count::count<diesel::sql_types::Integer, columns::id>>>`
+   = note: required because of the requirements on the impl of `Query` for `UpdateStatement<users::table, diesel::query_builder::where_clause::WhereClause<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<count::count::count<diesel::sql_types::Integer, columns::id>>>`
 
 error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggregates<diesel::expression::is_aggregate::Yes>` is not satisfied
   --> $DIR/custom_returning_requires_nonaggregate.rs:27:53
@@ -19,4 +19,4 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggreg
              <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 `(columns::name, count::count::count<diesel::sql_types::Text, columns::name>)`
-   = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<(columns::name, count::count::count<diesel::sql_types::Text, columns::name>)>>`
+   = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<(columns::name, count::count::count<diesel::sql_types::Text, columns::name>)>>`
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 d332a465ba6d..ff6ec4903a63 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
@@ -10,7 +10,7 @@ error[E0277]: the trait bound `bad::columns::age: SelectableExpression<users::ta
              <bad::columns::age as SelectableExpression<bad::table>>
              <bad::columns::age as SelectableExpression<diesel::query_source::joins::Join<Left, Right, Inner>>>
              <bad::columns::age as SelectableExpression<diesel::query_source::joins::Join<Left, Right, LeftOuter>>>
-   = note: required because of the requirements on the impl of `Query` for `UpdateStatement<users::table, diesel::query_builder::where_clause::WhereClause<Grouped<diesel::expression::operators::Eq<users::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<bad::columns::age>>`
+   = note: required because of the requirements on the impl of `Query` for `UpdateStatement<users::table, diesel::query_builder::where_clause::WhereClause<Grouped<diesel::expression::operators::Eq<users::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<bad::columns::age>>`
 
 error[E0277]: the trait bound `bad::columns::age: SelectableExpression<users::table>` is not satisfied
   --> $DIR/custom_returning_requires_selectable_expression.rs:33:63
@@ -25,7 +25,7 @@ error[E0277]: the trait bound `bad::columns::age: SelectableExpression<users::ta
              <bad::columns::age as SelectableExpression<diesel::query_source::joins::Join<Left, Right, Inner>>>
              <bad::columns::age as SelectableExpression<diesel::query_source::joins::Join<Left, Right, LeftOuter>>>
    = 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, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<(users::columns::name, bad::columns::age)>>`
+   = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<(users::columns::name, bad::columns::age)>>`
 
 error[E0277]: the trait bound `users::table: AppearsInFromClause<bad::table>` is not satisfied
   --> $DIR/custom_returning_requires_selectable_expression.rs:33:53
@@ -39,4 +39,4 @@ error[E0277]: the trait bound `users::table: AppearsInFromClause<bad::table>` is
    = 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, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<(users::columns::name, bad::columns::age)>>`
+   = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<(users::columns::name, bad::columns::age)>>`
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 b2ca42ccf8c2..3d67e772ed31 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,21 +1,27 @@
-error[E0277]: the trait bound `Sqlite: SupportsReturningClause` is not satisfied
+error[E0277]: the trait bound `ReturningClause<(columns::id, columns::name)>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
   --> $DIR/delete_statement_does_not_support_returning_methods_on_sqlite.rs:17:10
    |
 17 |         .get_result(&mut connection);
-   |          ^^^^^^^^^^ the trait `SupportsReturningClause` is not implemented for `Sqlite`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `ReturningClause<(columns::id, columns::name)>`
    |
-   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
+   = help: the following implementations were found:
+             <ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <ReturningClause<Expr> as QueryFragment<DB>>
+   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `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<Grouped<diesel::expression::operators::Eq<columns::name, diesel::expression::bound::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 `QueryFragment<Sqlite>` for `DeleteStatement<users::table, diesel::query_builder::where_clause::WhereClause<Grouped<diesel::expression::operators::Eq<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>>>, 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<Grouped<diesel::expression::operators::Eq<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>>>>`
 
-error[E0277]: the trait bound `Sqlite: SupportsReturningClause` is not satisfied
+error[E0277]: the trait bound `ReturningClause<columns::name>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
   --> $DIR/delete_statement_does_not_support_returning_methods_on_sqlite.rs:21:10
    |
 21 |         .get_result(&mut connection);
-   |          ^^^^^^^^^^ the trait `SupportsReturningClause` is not implemented for `Sqlite`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `ReturningClause<columns::name>`
    |
-   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
+   = help: the following implementations were found:
+             <ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <ReturningClause<Expr> as QueryFragment<DB>>
+   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `ReturningClause<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<Grouped<diesel::expression::operators::Eq<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>>>, diesel::query_builder::returning_clause::ReturningClause<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<Grouped<diesel::expression::operators::Eq<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>>>, diesel::query_builder::returning_clause::ReturningClause<columns::name>>`
+   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `DeleteStatement<users::table, diesel::query_builder::where_clause::WhereClause<Grouped<diesel::expression::operators::Eq<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>>>, ReturningClause<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<Grouped<diesel::expression::operators::Eq<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>>>, ReturningClause<columns::name>>`
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 c106eabf28ca..77a304bc80a5 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,21 +1,27 @@
-error[E0277]: the trait bound `Sqlite: SupportsReturningClause` is not satisfied
+error[E0277]: the trait bound `ReturningClause<(columns::id, columns::name)>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
   --> $DIR/insert_statement_does_not_support_returning_methods_on_sqlite.rs:29:10
    |
 29 |         .get_result::<User>(&mut connection);
-   |          ^^^^^^^^^^ the trait `SupportsReturningClause` is not implemented for `Sqlite`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `ReturningClause<(columns::id, columns::name)>`
    |
-   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
+   = help: the following implementations were found:
+             <ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <ReturningClause<Expr> as QueryFragment<DB>>
+   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `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, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>>`
+   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<(columns::id, columns::name)>>`
    = note: required because of the requirements on the impl of `LoadQuery<SqliteConnection, User>` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>>`
 
-error[E0277]: the trait bound `Sqlite: SupportsReturningClause` is not satisfied
+error[E0277]: the trait bound `ReturningClause<columns::name>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
   --> $DIR/insert_statement_does_not_support_returning_methods_on_sqlite.rs:34:10
    |
 34 |         .get_result::<String>(&mut connection);
-   |          ^^^^^^^^^^ the trait `SupportsReturningClause` is not implemented for `Sqlite`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `ReturningClause<columns::name>`
    |
-   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
+   = help: the following implementations were found:
+             <ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <ReturningClause<Expr> as QueryFragment<DB>>
+   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `ReturningClause<columns::name>`
    = note: 1 redundant requirements hidden
-   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<columns::name>>`
-   = note: required because of the requirements on the impl of `LoadQuery<SqliteConnection, std::string::String>` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<columns::name>>`
+   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<columns::name>>`
+   = note: required because of the requirements on the impl of `LoadQuery<SqliteConnection, std::string::String>` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<columns::name>>`
diff --git a/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.stderr b/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.stderr
index 9b90e14f0809..1c450153e091 100644
--- a/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.stderr
+++ b/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.stderr
@@ -1,3 +1,11 @@
+warning: use of deprecated function `diesel::dsl::any`: Use `ExpressionMethods::eq_any` instead
+  --> $DIR/pg_specific_expressions_cant_be_used_in_a_sqlite_query.rs:26:37
+   |
+26 |     users.select(id).filter(name.eq(any(Vec::<String>::new())))
+   |                                     ^^^
+   |
+   = note: `#[warn(deprecated)]` on by default
+
 error[E0271]: type mismatch resolving `<diesel::SqliteConnection as diesel::Connection>::Backend == Pg`
   --> $DIR/pg_specific_expressions_cant_be_used_in_a_sqlite_query.rs:27:10
    |
diff --git a/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.stderr b/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.stderr
index 05d713aa7dfe..7c4b33dcd4a3 100644
--- a/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.stderr
+++ b/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.stderr
@@ -1,16 +1,16 @@
-error[E0599]: no method named `returning` found for struct `DeleteStatement<users::table, diesel::query_builder::where_clause::WhereClause<Grouped<diesel::expression::operators::Eq<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>>>, diesel::query_builder::returning_clause::ReturningClause<columns::id>>` in the current scope
+error[E0599]: no method named `returning` found for struct `DeleteStatement<users::table, diesel::query_builder::where_clause::WhereClause<Grouped<diesel::expression::operators::Eq<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>>>, ReturningClause<columns::id>>` in the current scope
   --> $DIR/returning_cannot_be_called_twice.rs:23:11
    |
 23 |     query.returning(name);
    |           ^^^^^^^^^ private field, not a method
 
-error[E0599]: no method named `returning` found for struct `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<columns::id>>` in the current scope
+error[E0599]: no method named `returning` found for struct `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<columns::id>>` in the current scope
   --> $DIR/returning_cannot_be_called_twice.rs:28:11
    |
 28 |     query.returning(name);
    |           ^^^^^^^^^ private field, not a method
 
-error[E0599]: no method named `returning` found for struct `UpdateStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::update_statement::changeset::Assign<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<columns::id>>` in the current scope
+error[E0599]: no method named `returning` found for struct `UpdateStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::update_statement::changeset::Assign<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<columns::id>>` in the current scope
   --> $DIR/returning_cannot_be_called_twice.rs:33:11
    |
 33 |     query.returning(name);
diff --git a/diesel_compile_tests/tests/fail/returning_clause_requires_selectable_expression.stderr b/diesel_compile_tests/tests/fail/returning_clause_requires_selectable_expression.stderr
index 697dbdf5b9bf..83980f7a07ea 100644
--- a/diesel_compile_tests/tests/fail/returning_clause_requires_selectable_expression.stderr
+++ b/diesel_compile_tests/tests/fail/returning_clause_requires_selectable_expression.stderr
@@ -23,7 +23,7 @@ error[E0277]: the trait bound `non_users::columns::noname: SelectableExpression<
              <non_users::columns::noname as SelectableExpression<diesel::query_source::joins::Join<Left, Right, Inner>>>
              <non_users::columns::noname as SelectableExpression<diesel::query_source::joins::Join<Left, Right, LeftOuter>>>
              <non_users::columns::noname as SelectableExpression<non_users::table>>
-   = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<non_users::columns::noname>>`
+   = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<(DefaultableColumnInsertValue<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>,), users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<non_users::columns::noname>>`
 
 error[E0277]: the trait bound `non_users::columns::noname: SelectableExpression<users::table>` is not satisfied
   --> $DIR/returning_clause_requires_selectable_expression.rs:35:20
@@ -37,4 +37,4 @@ error[E0277]: the trait bound `non_users::columns::noname: SelectableExpression<
              <non_users::columns::noname as SelectableExpression<diesel::query_source::joins::Join<Left, Right, Inner>>>
              <non_users::columns::noname as SelectableExpression<diesel::query_source::joins::Join<Left, Right, LeftOuter>>>
              <non_users::columns::noname as SelectableExpression<non_users::table>>
-   = 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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<non_users::columns::noname>>`
+   = 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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<non_users::columns::noname>>`
diff --git a/diesel_compile_tests/tests/fail/selectable.stderr b/diesel_compile_tests/tests/fail/selectable.stderr
index 555672aa6411..e210a2f80cb4 100644
--- a/diesel_compile_tests/tests/fail/selectable.stderr
+++ b/diesel_compile_tests/tests/fail/selectable.stderr
@@ -218,7 +218,7 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::t
     = 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 `SelectBy<UserWithEmbeddedPost, _>`
-    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users::table>` is not satisfied
    --> $DIR/selectable.rs:172:10
@@ -235,7 +235,7 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users
     = 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 `SelectBy<UserWithEmbeddedPost, _>`
-    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Once`
    --> $DIR/selectable.rs:172:10
@@ -249,7 +249,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 `(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 `SelectBy<UserWithEmbeddedPost, _>`
-    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
    --> $DIR/selectable.rs:173:10
@@ -266,8 +266,8 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::t
     = 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 `SelectBy<UserWithEmbeddedPost, _>`
-    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
-    = note: required because of the requirements on the impl of `LoadQuery<_, UserWithEmbeddedPost>` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `LoadQuery<_, UserWithEmbeddedPost>` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users::table>` is not satisfied
    --> $DIR/selectable.rs:173:10
@@ -284,8 +284,8 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users
     = 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 `SelectBy<UserWithEmbeddedPost, _>`
-    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
-    = note: required because of the requirements on the impl of `LoadQuery<_, UserWithEmbeddedPost>` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `LoadQuery<_, UserWithEmbeddedPost>` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Once`
    --> $DIR/selectable.rs:173:10
@@ -299,8 +299,8 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
     = 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 `SelectBy<UserWithEmbeddedPost, _>`
-    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
-    = note: required because of the requirements on the impl of `LoadQuery<_, UserWithEmbeddedPost>` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `Query` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `LoadQuery<_, UserWithEmbeddedPost>` for `InsertStatement<users::table, ValuesClause<ColumnInsertValue<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
    --> $DIR/selectable.rs:180:10
@@ -317,7 +317,7 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::t
     = 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 `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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users::table>` is not satisfied
    --> $DIR/selectable.rs:180:10
@@ -334,7 +334,7 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users
     = 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 `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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Once`
    --> $DIR/selectable.rs:180:10
@@ -348,7 +348,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 `(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 `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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
    --> $DIR/selectable.rs:181:10
@@ -365,8 +365,8 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::t
     = 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 `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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users::table>` is not satisfied
    --> $DIR/selectable.rs:181:10
@@ -383,8 +383,8 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users
     = 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 `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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Once`
    --> $DIR/selectable.rs:181:10
@@ -398,8 +398,8 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
     = 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 `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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<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<users::columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::table>` is not satisfied
    --> $DIR/selectable.rs:187:10
@@ -461,8 +461,8 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression<users::t
     = 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 `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<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<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `Query` for `DeleteStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `LoadQuery<_, UserWithEmbeddedPost>` for `DeleteStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users::table>` is not satisfied
    --> $DIR/selectable.rs:188:10
@@ -479,8 +479,8 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression<users
     = 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 `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<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<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `Query` for `DeleteStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `LoadQuery<_, UserWithEmbeddedPost>` for `DeleteStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<posts::table>>::Count == diesel::query_source::Once`
    --> $DIR/selectable.rs:188:10
@@ -494,8 +494,8 @@ error[E0271]: type mismatch resolving `<users::table as AppearsInFromClause<post
     = 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 `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<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<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `Query` for `DeleteStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
+    = note: required because of the requirements on the impl of `LoadQuery<_, UserWithEmbeddedPost>` for `DeleteStatement<users::table, diesel::query_builder::where_clause::NoWhereClause, ReturningClause<SelectBy<UserWithEmbeddedPost, _>>>`
 
 error[E0599]: the function or associated item `as_select` exists for struct `UserWithoutSelectable`, but its trait bounds were not satisfied
    --> $DIR/selectable.rs:192:56
@@ -581,7 +581,7 @@ error[E0277]: the trait bound `SelectBy<Post, _>: SingleValue` is not satisfied
     |          ^^^^ the trait `SingleValue` is not implemented for `SelectBy<Post, _>`
     |
     = note: required because of the requirements on the impl of `CompatibleType<(i32, std::string::String, i32), _>` for `SelectBy<Post, _>`
-    = note: required because of the requirements on the impl of `LoadQuery<_, (i32, std::string::String, i32)>` for `InsertStatement<posts::table, ValuesClause<ColumnInsertValue<posts::columns::title, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, posts::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<SelectBy<Post, _>>>`
+    = note: required because of the requirements on the impl of `LoadQuery<_, (i32, std::string::String, i32)>` for `InsertStatement<posts::table, ValuesClause<ColumnInsertValue<posts::columns::title, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, posts::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<SelectBy<Post, _>>>`
 
 error[E0277]: the trait bound `(i32, std::string::String, i32): diesel::Queryable<SelectBy<Post, _>, _>` is not satisfied
    --> $DIR/selectable.rs:201:10
@@ -594,7 +594,7 @@ error[E0277]: the trait bound `(i32, std::string::String, i32): diesel::Queryabl
               <(A, B, C) as diesel::Queryable<Record<(SA, SB, SC)>, Pg>>
     = note: required because of the requirements on the impl of `FromSqlRow<SelectBy<Post, _>, _>` for `(i32, std::string::String, i32)`
     = note: required because of the requirements on the impl of `CompatibleType<(i32, std::string::String, i32), _>` for `SelectBy<Post, _>`
-    = note: required because of the requirements on the impl of `LoadQuery<_, (i32, std::string::String, i32)>` for `InsertStatement<posts::table, ValuesClause<ColumnInsertValue<posts::columns::title, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, posts::table>, diesel::query_builder::insert_statement::Insert, diesel::query_builder::returning_clause::ReturningClause<SelectBy<Post, _>>>`
+    = note: required because of the requirements on the impl of `LoadQuery<_, (i32, std::string::String, i32)>` for `InsertStatement<posts::table, ValuesClause<ColumnInsertValue<posts::columns::title, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, posts::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<SelectBy<Post, _>>>`
 
 error[E0271]: type mismatch resolving `<diesel::SqliteConnection as diesel::Connection>::Backend == Pg`
    --> $DIR/selectable.rs:210:10
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 e7caf81c2357..a3d6c4dbf823 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
@@ -1,3 +1,17 @@
+warning: use of deprecated function `diesel::dsl::any`: Use `ExpressionMethods::eq_any` instead
+  --> $DIR/subselect_cannot_reference_random_tables.rs:35:30
+   |
+35 |         .filter(users::id.eq(any(
+   |                              ^^^
+   |
+   = note: `#[warn(deprecated)]` on by default
+
+warning: use of deprecated function `diesel::dsl::any`: Use `ExpressionMethods::eq_any` instead
+  --> $DIR/subselect_cannot_reference_random_tables.rs:26:23
+   |
+26 |     use diesel::dsl::{any, exists};
+   |                       ^^^
+
 error[E0271]: type mismatch resolving `<diesel::query_source::joins::Join<posts::table, users::table, Inner> as AppearsInFromClause<comments::table>>::Count == diesel::query_source::Once`
   --> $DIR/subselect_cannot_reference_random_tables.rs:32:10
    |
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 bf43af7c4c13..1725120f40a0 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,21 +1,27 @@
-error[E0277]: the trait bound `Sqlite: SupportsReturningClause` is not satisfied
+error[E0277]: the trait bound `ReturningClause<(columns::id, columns::name)>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
   --> $DIR/update_statement_does_not_support_returning_methods_on_sqlite.rs:18:10
    |
 18 |         .get_result(&mut connection);
-   |          ^^^^^^^^^^ the trait `SupportsReturningClause` is not implemented for `Sqlite`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `ReturningClause<(columns::id, columns::name)>`
    |
-   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::name)>`
+   = help: the following implementations were found:
+             <ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <ReturningClause<Expr> as QueryFragment<DB>>
+   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `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<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<columns::name, diesel::expression::bound::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 `QueryFragment<Sqlite>` for `UpdateStatement<users::table, diesel::query_builder::where_clause::WhereClause<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, 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<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>>`
 
-error[E0277]: the trait bound `Sqlite: SupportsReturningClause` is not satisfied
+error[E0277]: the trait bound `ReturningClause<columns::name>: QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not satisfied
   --> $DIR/update_statement_does_not_support_returning_methods_on_sqlite.rs:23:10
    |
 23 |         .get_result(&mut connection);
-   |          ^^^^^^^^^^ the trait `SupportsReturningClause` is not implemented for `Sqlite`
+   |          ^^^^^^^^^^ the trait `QueryFragment<Sqlite, DoesNotSupportReturningClause>` is not implemented for `ReturningClause<columns::name>`
    |
-   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::returning_clause::ReturningClause<columns::name>`
+   = help: the following implementations were found:
+             <ReturningClause<Expr> as QueryFragment<DB, PgLikeReturningClause>>
+             <ReturningClause<Expr> as QueryFragment<DB>>
+   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `ReturningClause<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<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<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<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, diesel::query_builder::returning_clause::ReturningClause<columns::name>>`
+   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `UpdateStatement<users::table, diesel::query_builder::where_clause::WhereClause<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<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<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, diesel::query_builder::update_statement::changeset::Assign<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, ReturningClause<columns::name>>`
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 010a86f48233..ebf9af9bb9e3 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
@@ -1,10 +1,25 @@
-error[E0277]: the trait bound `Sqlite: SupportsDefaultKeyword` is not satisfied
+error[E0277]: the trait bound `BatchInsert<Vec<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, users::table, (), false>: QueryFragment<Sqlite, sqlite::backend::SqliteBatchInsert>` is not satisfied
   --> $DIR/upsert_with_multiple_values_not_supported_on_sqlite.rs:17:10
    |
 17 |         .execute(&mut connection);
-   |          ^^^^^^^ the trait `SupportsDefaultKeyword` is not implemented for `Sqlite`
+   |          ^^^^^^^ the trait `QueryFragment<Sqlite, sqlite::backend::SqliteBatchInsert>` is not implemented for `BatchInsert<Vec<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, users::table, (), false>`
    |
-   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `diesel::query_builder::insert_statement::batch_insert::BatchInsert<Vec<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, users::table, (), false>`
+   = help: the following implementations were found:
+             <BatchInsert<V, Tab, QId, HAS_STATIC_QUERY_ID> as QueryFragment<DB, PostgresLikeBatchInsertSupport>>
+             <BatchInsert<V, Tab, QId, HAS_STATIC_QUERY_ID> as QueryFragment<DB>>
+   = note: required because of the requirements on the impl of `QueryFragment<Sqlite>` for `BatchInsert<Vec<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, 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<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, 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<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, 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 `QueryFragment<Sqlite>` for `InsertStatement<users::table, diesel::query_builder::upsert::on_conflict_clause::OnConflictValues<BatchInsert<Vec<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, 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<BatchInsert<Vec<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, 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`
+  --> $DIR/upsert_with_multiple_values_not_supported_on_sqlite.rs:17:10
+   |
+17 |         .execute(&mut connection);
+   |          ^^^^^^^ expected struct `DoesNotSupportDefaultKeyword`, found struct `IsoSqlDefaultKeyword`
+   |
+   = note: required because of the requirements on the impl of `CanInsertInSingleQuery<Sqlite>` for `BatchInsert<Vec<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, users::table, (), false>`
+   = note: 1 redundant requirements hidden
+   = note: required because of the requirements on the impl of `CanInsertInSingleQuery<Sqlite>` for `diesel::query_builder::upsert::on_conflict_clause::OnConflictValues<BatchInsert<Vec<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, 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 `QueryFragment<Sqlite>` for `InsertStatement<users::table, diesel::query_builder::upsert::on_conflict_clause::OnConflictValues<BatchInsert<Vec<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, 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<BatchInsert<Vec<Grouped<diesel::expression::operators::Eq<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>, users::table, (), false>, diesel::query_builder::upsert::on_conflict_target::NoConflictTarget, diesel::query_builder::upsert::on_conflict_actions::DoNothing>>`
diff --git a/diesel_derives/tests/as_expression.rs b/diesel_derives/tests/as_expression.rs
index cc714ff22c85..ff55dd37b93b 100644
--- a/diesel_derives/tests/as_expression.rs
+++ b/diesel_derives/tests/as_expression.rs
@@ -1,5 +1,5 @@
 use diesel::backend::Backend;
-use diesel::deserialize::FromSql;
+use diesel::deserialize::{FromSql, FromSqlRow};
 use diesel::expression::AsExpression;
 use diesel::serialize::{Output, ToSql};
 use diesel::sql_types::Text;
diff --git a/diesel_tests/tests/debug/mod.rs b/diesel_tests/tests/debug/mod.rs
index 8bdd2ab36c4d..50e822f8c928 100644
--- a/diesel_tests/tests/debug/mod.rs
+++ b/diesel_tests/tests/debug/mod.rs
@@ -32,11 +32,6 @@ fn test_debug_output() {
 
 #[test]
 fn test_debug_batch_insert() {
-    // This test ensures that we've implemented `debug_query` for batch insert
-    // on sqlite
-    // This requires a separate impl because it's more than one sql statement that
-    // is executed
-
     use crate::schema::users::dsl::*;
 
     let values = vec![
@@ -69,32 +64,6 @@ fn test_debug_batch_insert() {
             owned_sql_debug,
             r#"Query { sql: "INSERT INTO \"users\" (\"name\", \"hair_color\") VALUES ($1, $2), ($3, $4)", binds: ["Sean", Some("black"), "Tess", None] }"#
         );
-    } else if cfg!(feature = "sqlite") {
-        assert_eq!(
-            borrowed_sql_display,
-            r#"BEGIN;
-INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Sean", Some("black")]
-INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Tess", None]
-COMMIT;
-"#
-        );
-        assert_eq!(
-            borrowed_sql_debug,
-            r#"Query { sql: ["BEGIN", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Sean\", Some(\"black\")]", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Tess\", None]", "COMMIT"], binds: [] }"#
-        );
-
-        assert_eq!(
-            owned_sql_display,
-            r#"BEGIN;
-INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Sean", Some("black")]
-INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Tess", None]
-COMMIT;
-"#
-        );
-        assert_eq!(
-            owned_sql_debug,
-            r#"Query { sql: ["BEGIN", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Sean\", Some(\"black\")]", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Tess\", None]", "COMMIT"], binds: [] }"#
-        );
     } else {
         assert_eq!(
             borrowed_sql_display,
@@ -116,6 +85,55 @@ COMMIT;
     }
 }
 
+#[test]
+#[cfg(feature = "sqlite")]
+fn test_insert_with_default() {
+    // This test ensures that we've implemented `debug_query` for batch insert
+    // containing a default value on sqlite
+    // This requires a separate impl because it's more than one sql statement that
+    // is executed
+
+    use crate::schema::users::dsl::*;
+
+    let values = vec![
+        (Some(name.eq("Sean")), hair_color.eq(Some("black"))),
+        (Some(name.eq("Tess")), hair_color.eq(None::<&str>)),
+    ];
+    let borrowed_command = insert_into(users).values(&values);
+    let borrowed_sql_display = debug_query::<TestBackend, _>(&borrowed_command).to_string();
+    let borrowed_sql_debug = format!("{:?}", debug_query::<TestBackend, _>(&borrowed_command));
+
+    let owned_command = insert_into(users).values(values);
+    let owned_sql_display = debug_query::<TestBackend, _>(&owned_command).to_string();
+    let owned_sql_debug = format!("{:?}", debug_query::<TestBackend, _>(&owned_command));
+
+    assert_eq!(
+        borrowed_sql_display,
+        r#"BEGIN;
+INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Sean", Some("black")]
+INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Tess", None]
+COMMIT;
+"#
+    );
+    assert_eq!(
+        borrowed_sql_debug,
+        r#"Query { sql: ["BEGIN", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Sean\", Some(\"black\")]", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Tess\", None]", "COMMIT"], binds: [] }"#
+    );
+
+    assert_eq!(
+        owned_sql_display,
+        r#"BEGIN;
+INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Sean", Some("black")]
+INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Tess", None]
+COMMIT;
+"#
+    );
+    assert_eq!(
+        owned_sql_debug,
+        r#"Query { sql: ["BEGIN", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Sean\", Some(\"black\")]", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Tess\", None]", "COMMIT"], binds: [] }"#
+    );
+}
+
 #[test]
 #[cfg(feature = "postgres")]
 fn test_upsert() {
diff --git a/diesel_tests/tests/filter.rs b/diesel_tests/tests/filter.rs
index 1b136d0d2f6a..4baae9b07b5f 100644
--- a/diesel_tests/tests/filter.rs
+++ b/diesel_tests/tests/filter.rs
@@ -589,6 +589,7 @@ fn filter_subselect_with_nullable_column() {
 
 #[test]
 #[cfg(feature = "postgres")]
+#[allow(deprecated)]
 fn filter_subselect_with_pg_any() {
     use diesel::dsl::any;
 
diff --git a/diesel_tests/tests/filter_operators.rs b/diesel_tests/tests/filter_operators.rs
index d0fd7a786962..59df0c0d9388 100644
--- a/diesel_tests/tests/filter_operators.rs
+++ b/diesel_tests/tests/filter_operators.rs
@@ -206,6 +206,7 @@ fn filter_by_ilike() {
 }
 
 #[test]
+#[allow(deprecated)]
 #[cfg(feature = "postgres")]
 fn filter_by_any() {
     use crate::schema::users::dsl::*;
@@ -246,7 +247,7 @@ fn filter_by_in() {
     let jim = User::new(3, "Jim");
 
     let owned_names = vec!["Sean", "Tess"];
-    let borrowed_names: &[_] = &["Sean", "Jim"];
+    let borrowed_names: &[&str] = &["Sean", "Jim"];
     assert_eq!(
         vec![sean.clone(), tess],
         users
diff --git a/diesel_tests/tests/group_by.rs b/diesel_tests/tests/group_by.rs
index b5623b81f724..d4506f700299 100644
--- a/diesel_tests/tests/group_by.rs
+++ b/diesel_tests/tests/group_by.rs
@@ -196,19 +196,27 @@ fn check_filter_with_group_by_subselect() {
         .filter(posts::id.nullable().eq_any(subselect))
         .select((posts::user_id, posts::title));
 
-    let mut expected_sql = "SELECT `posts`.`user_id`, `posts`.`title` \
-                            FROM `posts` \
-                            WHERE (\
-                              `posts`.`id` IN (\
-                              SELECT min(`posts`.`id`) \
-                              FROM `posts` \
-                              GROUP BY `posts`.`user_id`)) \
-                            -- binds: []"
-        .to_string();
-
-    if cfg!(feature = "postgres") {
-        expected_sql = expected_sql.replace('`', "\"");
-    }
+    let expected_sql = if cfg!(feature = "postgres") {
+        "SELECT \"posts\".\"user_id\", \"posts\".\"title\" \
+         FROM \"posts\" \
+         WHERE (\
+         \"posts\".\"id\" = ANY(\
+         SELECT min(\"posts\".\"id\") \
+         FROM \"posts\" \
+         GROUP BY \"posts\".\"user_id\")) \
+         -- binds: []"
+            .to_string()
+    } else {
+        "SELECT `posts`.`user_id`, `posts`.`title` \
+         FROM `posts` \
+         WHERE (\
+         `posts`.`id` IN (\
+         SELECT min(`posts`.`id`) \
+         FROM `posts` \
+         GROUP BY `posts`.`user_id`)) \
+         -- binds: []"
+            .to_string()
+    };
 
     assert_eq!(expected_sql, debug_query(&source).to_string());
 
@@ -230,19 +238,27 @@ fn check_filter_with_boxed_group_by_subselect() {
         .filter(posts::id.nullable().eq_any(subselect))
         .select((posts::user_id, posts::title));
 
-    let mut expected_sql = "SELECT `posts`.`user_id`, `posts`.`title` \
-                            FROM `posts` \
-                            WHERE (\
-                              `posts`.`id` IN (\
-                              SELECT min(`posts`.`id`) \
-                              FROM `posts` \
-                              GROUP BY `posts`.`user_id`)) \
-                            -- binds: []"
-        .to_string();
-
-    if cfg!(feature = "postgres") {
-        expected_sql = expected_sql.replace('`', "\"");
-    }
+    let expected_sql = if cfg!(feature = "postgres") {
+        "SELECT \"posts\".\"user_id\", \"posts\".\"title\" \
+         FROM \"posts\" \
+         WHERE (\
+         \"posts\".\"id\" = ANY(\
+         SELECT min(\"posts\".\"id\") \
+         FROM \"posts\" \
+         GROUP BY \"posts\".\"user_id\")) \
+         -- binds: []"
+            .to_string()
+    } else {
+        "SELECT `posts`.`user_id`, `posts`.`title` \
+         FROM `posts` \
+         WHERE (\
+         `posts`.`id` IN (\
+         SELECT min(`posts`.`id`) \
+         FROM `posts` \
+         GROUP BY `posts`.`user_id`)) \
+         -- binds: []"
+            .to_string()
+    };
 
     assert_eq!(expected_sql, debug_query(&source).to_string());
 
diff --git a/diesel_tests/tests/insert.rs b/diesel_tests/tests/insert.rs
index eeb6a07afed8..0d1796c2ac28 100644
--- a/diesel_tests/tests/insert.rs
+++ b/diesel_tests/tests/insert.rs
@@ -701,3 +701,40 @@ fn batch_insert_is_atomic_on_sqlite() {
 
     assert_eq!(Ok(0), users.count().get_result(connection));
 }
+
+// regression test for https://github.com/diesel-rs/diesel/issues/2898
+#[test]
+fn mixed_defaultable_insert() {
+    use crate::schema::users;
+
+    #[derive(Insertable)]
+    struct User {
+        name: &'static str,
+    }
+
+    #[derive(Insertable)]
+    #[table_name = "users"]
+    struct UserHairColor {
+        hair_color: &'static str,
+    }
+
+    let conn = &mut connection();
+
+    diesel::insert_into(users::table)
+        .values((
+            &User { name: "Bob" },
+            &Some(UserHairColor {
+                hair_color: "Green",
+            }),
+        ))
+        .execute(conn)
+        .unwrap();
+
+    let actual_data = users::table
+        .select((users::name, users::hair_color))
+        .load(conn);
+
+    let expected_data = vec![("Bob".to_string(), Some("Green".to_string()))];
+
+    assert_eq!(Ok(expected_data), actual_data);
+}
diff --git a/diesel_tests/tests/types.rs b/diesel_tests/tests/types.rs
index 524bd1fdb726..60c229165c07 100644
--- a/diesel_tests/tests/types.rs
+++ b/diesel_tests/tests/types.rs
@@ -1259,7 +1259,7 @@ use std::fmt::Debug;
 fn query_to_sql_equality<T, U>(sql_str: &str, value: U) -> bool
 where
     U: AsExpression<T> + Debug + Clone,
-    U::Expression: SelectableExpression<(), SqlType = T>
+    U::Expression: SelectableExpression<diesel::query_builder::NoFromClause, SqlType = T>
         + ValidGrouping<(), IsAggregate = is_aggregate::Never>,
     U::Expression: QueryFragment<TestBackend> + QueryId,
     T: QueryId + SingleValue + SqlType,
diff --git a/diesel_tests/tests/types_roundtrip.rs b/diesel_tests/tests/types_roundtrip.rs
index 4296e65db6eb..fc18d7ef5b9e 100644
--- a/diesel_tests/tests/types_roundtrip.rs
+++ b/diesel_tests/tests/types_roundtrip.rs
@@ -28,7 +28,7 @@ where
         + Clone
         + ::std::fmt::Debug
         + 'static,
-    <T as AsExpression<ST>>::Expression: SelectableExpression<(), SqlType = ST>
+    <T as AsExpression<ST>>::Expression: SelectableExpression<diesel::query_builder::NoFromClause, SqlType = ST>
         + NonAggregate
         + QueryFragment<<TestConnection as Connection>::Backend>
         + QueryId,