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

Issue:
minor: create_database_if_needed assumes URL is a path
Gonna ignore the template since I just found this from reading diesel_cli's source; sorry if that's a problem.

```
/// Creates the database specified in the connection url. It returns an error
/// it was unable to create the database.
fn create_database_if_needed(database_url: &str) -> DatabaseResult<()> {
    match Backend::for_url(database_url) {
        #[cfg(feature = "postgres")]
        Backend::Pg => {
            if PgConnection::establish(database_url).is_err() {
                let (database, postgres_url) = change_database_of_url(database_url, "postgres");
                println!("Creating database: {}", database);
                let mut conn = PgConnection::establish(&postgres_url)?;
                query_helper::create_database(&database).execute(&mut conn)?;
            }
        }
        #[cfg(feature = "sqlite")]
        Backend::Sqlite => {
            if !::std::path::Path::new(database_url).exists() {
                println!("Creating database: {}", database_url);
                SqliteConnection::establish(database_url)?;
            }
        }
        #[cfg(feature = "mysql")]
        Backend::Mysql => {
            if MysqlConnection::establish(database_url).is_err() {
                let (database, mysql_url) =
                    change_database_of_url(database_url, "information_schema");
                println!("Creating database: {}", database);
                let mut conn = MysqlConnection::establish(&mysql_url)?;
                query_helper::create_database(&database).execute(&mut conn)?;
            }
        }
    }

    Ok(())
}
```

[Permalink to problem line](https://github.com/diesel-rs/diesel/blob/1327fba7b2d0419b631e4ff24e4ca430d62fc2fe/diesel_cli/src/database.rs#L175).

The `Backend::Sqlite` case assumes that `database_url` is a bare path (as opposed to, say, a `file:` URL, which is otherwise valid) when checking if the path exists, so it may enter the wrong branch if given a non-path argument (e.g. if given a `file:///foo/bar` url, this code seems to check for a relative path `file:/foo/bar` instead of an absolute path `/foo/bar`).
RUSTSEC-2021-0139: ansi_term is Unmaintained

> ansi_term is Unmaintained

| Details             |                                                |
| ------------------- | ---------------------------------------------- |
| Status              | unmaintained                |
| Package             | `ansi_term`                      |
| Version             | `0.12.1`                   |
| URL                 | [https://github.com/ogham/rust-ansi-term/issues/72](https://github.com/ogham/rust-ansi-term/issues/72) |
| Date                | 2021-08-18                         |

The maintainer has adviced this crate is deprecated and will not
receive any maintenance.

The crate does not seem to have much dependencies and may or may not be ok to use as-is.

Last release seems to have been three years ago.

## Possible Alternative(s)

 The below list has not been vetted in any way and may or may not contain alternatives;

 - [anstyle](https://github.com/epage/anstyle)
 - [console](https://crates.io/crates/console)
 - [nu-ansi-term](https://crates.io/crates/nu-ansi-term)
 - [yansi](https://crates.io/crates/yansi)

See [advisory page](https://rustsec.org/advisories/RUSTSEC-2021-0139.html) for additional details.

Aliases with group_by and select
<!--
If you want to report a bug, we added some points below which help us track down the problem faster.
-->

## Setup

### Versions

- **Rust:** rustc 1.63.0 (4b91a6ea7 2022-08-08)
- **Diesel:** 2.0.0
- **Database:** PostgreSQL 13
- **Operating System** Linux (Ubuntu 22.04)

### Feature Flags

- **diesel:** postgres, uuid, chrono

## Problem Description
I'm trying to add second alias to query with left_join and failing.
I have the following code which compiles fine:
```rust
let leafs = diesel::alias!(chunks as leafs);
let mut query = chunks::table
    .left_join(
        leafs.on(chunks::path
            .contains(leafs.field(chunks::path))
            .and(leafs.field(chunks::nchildren).eq(0))),
    )
    .group_by(chunks::id)
    .select((
        chunks::all_columns,
        sum(leafs.field(chunks::estimated).nullable()),
    ))
    .into_boxed();
```
But if I'm converting it to this, it fails to compile:
```rust
let (c, leafs) = diesel::alias!(chunks as c, chunks as leafs);
let mut query = c
    .left_join(
        leafs.on(c
            .field(chunks::path)
            .contains(leafs.field(chunks::path))
            .and(leafs.field(chunks::nchildren).eq(0))),
    )
    .group_by(c.field(chunks::id))
    .select((
        c.fields(chunks::all_columns),
        sum(leafs.field(chunks::estimated).nullable()),
    ))
    .into_boxed();
```

### What are you trying to accomplish?
I'm trying to add alias for main self-referencing table to make query more complex later

### What is the expected output?
It should compile :)

### What is the actual output?
```
60 |             .select((
   |              ^^^^^^ the trait `ValidGrouping<AliasedField<c, chunks::columns::id>>` is not implemented for `AliasedField<c, chunks::columns::parent_id>`
60 |             .select((
   |              ^^^^^^ the trait `ValidGrouping<AliasedField<c, chunks::columns::id>>` is not implemented for `AliasedField<c, chunks::columns::path>`
60 |             .select((
   |              ^^^^^^ the trait `ValidGrouping<AliasedField<c, chunks::columns::id>>` is not implemented for `AliasedField<c, chunks::columns::label>`
... and so on for each field in chunk model
```

### Are you seeing any additional errors?


### Steps to reproduce
corresponding model is the following:
```rust
diesel::table! {
    use diesel::sql_types::*;
    use diesel_ltree::sql_types::*;

    chunks (id) {
        id -> Int8,
        parent_id -> Nullable<Int8>,
        path -> Ltree,
        label -> Text,
        estimated -> Int4,
        nchildren -> Int4,
    }
}
```

<!--
Please include as much of your codebase as needed to reproduce the error.  If the relevant files are large, please consider linking to a public repository or a [Gist](https://gist.github.com/). This includes normally the following parts:

* The exact code where your hit the problem
* Relevant parts your schema, so any `table!` macro calls required for the
* Any other type definitions involved in the code, which produces your problem
-->

## Checklist

- [x] I have already looked over the [issue tracker](https://github.com/diesel-rs/diesel/issues)  and the [disussion forum](https://github.com/diesel-rs/diesel/discussions)  for similar possible closed issues.
<!--
If you are unsure if your issue is a duplicate of an existing issue please link the issue in question here
--> 
- [x] This issue can be reproduced on Rust's stable channel. (Your issue will be
  closed if this is not the case)
- [x] This issue can be reproduced without requiring a third party crate

<!--
Thank you for your submission!  You're helping make Diesel more robust 🎉

We'll try to respond as quickly as possible.
-->

Upsert with where clause Postgres implementation is wrong
## Problem Description

Using `on_conflict(...).with_target(...)` is supposed to limit the rows updated during an upsert, but the implementation is slightly wrong. As a result no row is actually being limited. (code here: https://github.com/diesel-rs/diesel/blob/v2.0.0/diesel/src/query_builder/upsert/on_conflict_target_decorations.rs#L19)

Note, the current implementation actually solves a different problem around index predicate but I don't believe that it was the intention of the original issue (https://github.com/diesel-rs/diesel/issues/2430). 

## Details
For example, looking at the test file (https://github.com/diesel-rs/diesel/blob/master/diesel_tests/tests/debug/mod.rs#L158), we would potentially get back an sql statement that doesn't work as intended. 
```
INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) ON CONFLICT ("hair_color") WHERE "users"."hair_color" = $5 DO NOTHING
-- binds ...
```

The `WHERE` clause should actually be moved to the end, otherwise it does nothing. 

For example, according to the postgres documentation (https://www.postgresql.org/docs/current/sql-insert.html), `WHERE` needs to happen after `DO UPDATE SET...`. 
```
-- Don't update existing distributors based in a certain ZIP code
INSERT INTO distributors AS d (did, dname) VALUES (8, 'Anvil Distribution')
    ON CONFLICT (did) DO UPDATE
    SET dname = EXCLUDED.dname || ' (formerly ' || d.dname || ')'
    WHERE d.zipcode <> '21201';
```


## Repro
I tested in a postgresql DB with a trivial example: 
```
create table test(
    name text primary key,
    version int    
);

insert into test values ('a', 5)

-- this works as intended, row is not updated
insert into test ("name", "version") values ('a', 3) on conflict ("name") 
do update set "version" = excluded."version" where test."version" < 1;


-- moving where right after on conflict is wrong. row will be updated regardless what the condition is
insert into test ("name", "version") values ('a', 3) on conflict ("name") where test."version" < 1
do update set "version" = excluded."version" 




Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a497c98a63fd..7202323cb4a7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -120,9 +120,10 @@ jobs:
       - name: Install postgres (MacOS)
         if: runner.os == 'macOS' && matrix.backend == 'postgres'
         run: |
-          /usr/local/opt/postgres/bin/pg_ctl -D /usr/local/var/postgres start
+          initdb -D /usr/local/var/postgres
+          pg_ctl -D /usr/local/var/postgres start
           sleep 3
-          /usr/local/opt/postgres/bin/createuser -s postgres
+          createuser -s postgres
           echo "PG_DATABASE_URL=postgres://postgres@localhost/" >> $GITHUB_ENV
           echo "PG_EXAMPLE_DATABASE_URL=postgres://postgres@localhost/diesel_example" >> $GITHUB_ENV
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a0c5c54eda60..ea5f90c04504 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,16 @@ Increasing the minimal supported Rust version will always be coupled at least wi
 
 ## Unreleased 
 
+## [2.0.1] 2022-10-xx
+
+### Fixed
+
+* Fixed an issue with `diesel_cli` generating incompatible type names for the `generate_missing_sql_type_definitions` feature on PostgreSQL
+* Fixed an issue how `diesel_cli` handles sqlite urls while checking if a given database exists
+* Fixed an issue with `PgConnection` becoming unusable after hitting a database error in certain situations
+* Fixed an issue with diesel generating invalid SQL for certain `INSERT … ON CONFLICT` queries
+* Fixed `diesel_derives` generating code that triggers the disabled by default `unused_qualifications` lint
+
 ## [2.0.0] 2022-08-29
 
 ### Added
@@ -1957,3 +1967,4 @@ queries or set `PIPES_AS_CONCAT` manually.
 [2.0.0 Rc0]: https://github.com/diesel-rs/diesel/compare/v.1.4.0...v2.0.0-rc0
 [2.0.0 Rc1]: https://github.com/diesel-rs/diesel/compare/v.2.0.0-rc0...v2.0.0-rc1
 [2.0.0]: https://github.com/diesel-rs/diesel/compare/v.1.4.0...v2.0.0
+[2.0.1]: https://github.com/diesel-rs/diesel/compare/v.2.0.0...v2.0.1
diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml
index dac80110425a..9852c62c9c6f 100644
--- a/diesel/Cargo.toml
+++ b/diesel/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "diesel"
-version = "2.0.0"
+version = "2.0.1"
 license = "MIT OR Apache-2.0"
 description = "A safe, extensible ORM and Query Builder for PostgreSQL, SQLite, and MySQL"
 readme = "README.md"
diff --git a/diesel/src/expression_methods/global_expression_methods.rs b/diesel/src/expression_methods/global_expression_methods.rs
index fb1770335136..893867a0bf8f 100644
--- a/diesel/src/expression_methods/global_expression_methods.rs
+++ b/diesel/src/expression_methods/global_expression_methods.rs
@@ -9,6 +9,25 @@ use crate::sql_types::{SingleValue, SqlType};
 pub trait ExpressionMethods: Expression + Sized {
     /// Creates a SQL `=` expression.
     ///
+    /// Note that this function follows SQL semantics around `None`/`null` values,
+    /// so `eq(None)` will never match. Use [`is_null`](ExpressionMethods::is_null()) instead.
+    ///
+    ///
+    #[cfg_attr(
+        any(feature = "sqlite", feature = "postgres"),
+        doc = "To get behavior that is more like the Rust `=` operator you can also use the"
+    )]
+    #[cfg_attr(
+        feature = "sqlite",
+        doc = "sqlite-specific [`is`](crate::SqliteExpressionMethods::is())"
+    )]
+    #[cfg_attr(all(feature = "sqlite", feature = "postgres"), doc = "or the")]
+    #[cfg_attr(
+        feature = "postgres",
+        doc = "postgres-specific [`is_not_distinct_from`](crate::PgExpressionMethods::is_not_distinct_from())"
+    )]
+    #[cfg_attr(any(feature = "sqlite", feature = "postgres"), doc = ".")]
+    ///
     /// # Example
     ///
     /// ```rust
@@ -21,6 +40,33 @@ pub trait ExpressionMethods: Expression + Sized {
     /// assert_eq!(Ok(1), data.first(connection));
     /// # }
     /// ```
+    ///
+    /// Matching against `None` follows SQL semantics:
+    /// ```rust
+    /// # include!("../doctest_setup.rs");
+    /// #
+    /// # fn main() {
+    /// #     run_test().unwrap();
+    /// # }
+    /// #
+    /// # fn run_test() -> QueryResult<()> {
+    /// #     use schema::animals::dsl::*;
+    /// #     let connection = &mut establish_connection();
+    /// #
+    /// let data = animals
+    ///     .select(species)
+    ///     .filter(name.eq::<Option<String>>(None))
+    ///     .first::<String>(connection);
+    /// assert_eq!(Err(diesel::NotFound), data);
+    ///
+    /// let data = animals
+    ///     .select(species)
+    ///     .filter(name.is_null())
+    ///     .first::<String>(connection)?;
+    /// assert_eq!("spider", data);
+    /// #     Ok(())
+    /// # }
+    /// ```
     #[doc(alias = "=")]
     fn eq<T>(self, other: T) -> dsl::Eq<Self, T>
     where
@@ -157,6 +203,7 @@ pub trait ExpressionMethods: Expression + Sized {
     /// assert_eq!("spider", data);
     /// #     Ok(())
     /// # }
+    /// ```
     // This method is part of the public API,
     // so we cannot just change the name to appease clippy
     // (Otherwise it's also named after the `IS NULL` sql expression
@@ -188,6 +235,7 @@ pub trait ExpressionMethods: Expression + Sized {
     /// assert_eq!("dog", data);
     /// #     Ok(())
     /// # }
+    /// ```
     // This method is part of the public API,
     // so we cannot just change the name to appease clippy
     // (Otherwise it's also named after the `IS NOT NULL` sql expression
@@ -311,6 +359,7 @@ pub trait ExpressionMethods: Expression + Sized {
     /// assert_eq!("Sean", data);
     /// #     Ok(())
     /// # }
+    /// ```
     #[doc(alias = "<=")]
     fn le<T>(self, other: T) -> dsl::LtEq<Self, T>
     where
@@ -375,6 +424,7 @@ pub trait ExpressionMethods: Expression + Sized {
     /// assert_eq!("spider", data);
     /// #     Ok(())
     /// # }
+    /// ```
     fn not_between<T, U>(self, lower: T, upper: U) -> dsl::NotBetween<Self, T, U>
     where
         Self::SqlType: SqlType,
diff --git a/diesel/src/migration/mod.rs b/diesel/src/migration/mod.rs
index afd631c2786d..735aaf42ab3a 100644
--- a/diesel/src/migration/mod.rs
+++ b/diesel/src/migration/mod.rs
@@ -142,37 +142,37 @@ pub trait MigrationSource<DB: Backend> {
 
 impl<'a, DB: Backend> Migration<DB> for Box<dyn Migration<DB> + 'a> {
     fn run(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
-        (&**self).run(conn)
+        (**self).run(conn)
     }
 
     fn revert(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
-        (&**self).revert(conn)
+        (**self).revert(conn)
     }
 
     fn metadata(&self) -> &dyn MigrationMetadata {
-        (&**self).metadata()
+        (**self).metadata()
     }
 
     fn name(&self) -> &dyn MigrationName {
-        (&**self).name()
+        (**self).name()
     }
 }
 
 impl<'a, DB: Backend> Migration<DB> for &'a dyn Migration<DB> {
     fn run(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
-        (&**self).run(conn)
+        (**self).run(conn)
     }
 
     fn revert(&self, conn: &mut dyn BoxableConnection<DB>) -> Result<()> {
-        (&**self).revert(conn)
+        (**self).revert(conn)
     }
 
     fn metadata(&self) -> &dyn MigrationMetadata {
-        (&**self).metadata()
+        (**self).metadata()
     }
 
     fn name(&self) -> &dyn MigrationName {
-        (&**self).name()
+        (**self).name()
     }
 }
 
diff --git a/diesel/src/pg/connection/result.rs b/diesel/src/pg/connection/result.rs
index 3036c5d7ec1d..b6169ae6a9a8 100644
--- a/diesel/src/pg/connection/result.rs
+++ b/diesel/src/pg/connection/result.rs
@@ -48,6 +48,12 @@ impl PgResult {
                 ))
             }
             _ => {
+                // "clearing" the connection by polling result till we get a null.
+                // this will indicate that the previous command is complete and
+                // the same connection is ready to process next command.
+                // https://www.postgresql.org/docs/current/libpq-async.html
+                while conn.get_next_result().map_or(true, |r| r.is_some()) {}
+
                 let mut error_kind =
                     match get_result_field(internal_result.as_ptr(), ResultField::SqlState) {
                         Some(error_codes::UNIQUE_VIOLATION) => DatabaseErrorKind::UniqueViolation,
diff --git a/diesel/src/pg/query_builder/query_fragment_impls.rs b/diesel/src/pg/query_builder/query_fragment_impls.rs
index e90191242a79..47035742b874 100644
--- a/diesel/src/pg/query_builder/query_fragment_impls.rs
+++ b/diesel/src/pg/query_builder/query_fragment_impls.rs
@@ -5,6 +5,8 @@ use crate::pg::Pg;
 use crate::query_builder::locking_clause::{
     ForKeyShare, ForNoKeyUpdate, ForShare, ForUpdate, NoModifier, NoWait, SkipLocked,
 };
+use crate::query_builder::upsert::on_conflict_actions::DoUpdate;
+use crate::query_builder::upsert::on_conflict_clause::OnConflictValues;
 use crate::query_builder::upsert::on_conflict_target_decorations::DecoratedConflictTarget;
 use crate::query_builder::{AstPass, QueryFragment};
 use crate::result::QueryResult;
@@ -98,15 +100,20 @@ where
     }
 }
 
-impl<T, U> QueryFragment<Pg, crate::pg::backend::PgOnConflictClaues>
-    for DecoratedConflictTarget<T, U>
+impl<Values, Target, Action, Where> QueryFragment<Pg, crate::pg::backend::PgOnConflictClaues>
+    for OnConflictValues<Values, DecoratedConflictTarget<Target, Where>, DoUpdate<Action>>
 where
-    T: QueryFragment<Pg>,
-    U: QueryFragment<Pg>,
+    Values: QueryFragment<Pg>,
+    Target: QueryFragment<Pg>,
+    DoUpdate<Action>: QueryFragment<Pg>,
+    Where: QueryFragment<Pg>,
 {
     fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Pg>) -> QueryResult<()> {
-        self.target.walk_ast(out.reborrow())?;
-        self.where_clause.walk_ast(out.reborrow())?;
+        self.values.walk_ast(out.reborrow())?;
+        out.push_sql(" ON CONFLICT");
+        self.target.target.walk_ast(out.reborrow())?;
+        self.action.walk_ast(out.reborrow())?;
+        self.target.where_clause.walk_ast(out.reborrow())?;
         Ok(())
     }
 }
diff --git a/diesel/src/query_builder/insert_statement/mod.rs b/diesel/src/query_builder/insert_statement/mod.rs
index b185d7c45ad3..51e6edd92436 100644
--- a/diesel/src/query_builder/insert_statement/mod.rs
+++ b/diesel/src/query_builder/insert_statement/mod.rs
@@ -122,8 +122,6 @@ where
     }
 }
 
-#[derive(Debug, Copy, Clone)]
-#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
 /// A fully constructed insert statement.
 ///
 /// The parameters of this struct represent:
@@ -136,10 +134,22 @@ where
 /// - `Ret`: The `RETURNING` clause of the query. The specific types used to
 ///   represent this are private. You can safely rely on the default type
 ///   representing a query without a `RETURNING` clause.
+#[diesel_derives::__diesel_public_if(
+    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
+    public_fields(operator, target, records, returning)
+)]
+#[derive(Debug, Copy, Clone)]
+#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
 pub struct InsertStatement<T: QuerySource, U, Op = Insert, Ret = NoReturningClause> {
+    /// The operator used by this InsertStatement
+    ///
+    /// Corresponds to either `Insert` or `Replace`
     operator: Op,
+    /// The table we are inserting into
     target: T,
+    /// The data which should be inserted
     records: U,
+    /// An optional returning clause
     returning: Ret,
     into_clause: T::FromClause,
 }
@@ -160,7 +170,11 @@ where
 }
 
 impl<T: QuerySource, U, Op, Ret> InsertStatement<T, U, Op, Ret> {
-    fn new(target: T, records: U, operator: Op, returning: Ret) -> Self {
+    /// Create a new InsertStatement instance
+    #[diesel_derives::__diesel_public_if(
+        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+    )]
+    pub(crate) fn new(target: T, records: U, operator: Op, returning: Ret) -> Self {
         InsertStatement {
             into_clause: target.from_clause(),
             operator,
diff --git a/diesel/src/query_builder/select_clause.rs b/diesel/src/query_builder/select_clause.rs
index 19182d88745e..bcbed30fe3a8 100644
--- a/diesel/src/query_builder/select_clause.rs
+++ b/diesel/src/query_builder/select_clause.rs
@@ -6,7 +6,7 @@ use crate::query_source::QuerySource;
 
 #[doc(hidden)]
 pub struct DefaultSelectClause<QS: AsQuerySource> {
-    default_seletion: <QS::QuerySource as QuerySource>::DefaultSelection,
+    default_selection: <QS::QuerySource as QuerySource>::DefaultSelection,
 }
 
 impl<QS> std::fmt::Debug for DefaultSelectClause<QS>
@@ -16,7 +16,7 @@ where
 {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         f.debug_struct("DefaultSelectClause")
-            .field("default_seletion", &self.default_seletion)
+            .field("default_selection", &self.default_selection)
             .finish()
     }
 }
@@ -28,7 +28,7 @@ where
 {
     fn clone(&self) -> Self {
         Self {
-            default_seletion: self.default_seletion.clone(),
+            default_selection: self.default_selection.clone(),
         }
     }
 }
@@ -43,7 +43,7 @@ where
 impl<QS: AsQuerySource> DefaultSelectClause<QS> {
     pub(crate) fn new(qs: &QS) -> Self {
         Self {
-            default_seletion: qs.as_query_source().default_selection(),
+            default_selection: qs.as_query_source().default_selection(),
         }
     }
 }
@@ -119,6 +119,6 @@ where
     <QS::QuerySource as QuerySource>::DefaultSelection: QueryFragment<DB>,
 {
     fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
-        self.default_seletion.walk_ast(pass)
+        self.default_selection.walk_ast(pass)
     }
 }
diff --git a/diesel/src/query_builder/select_statement/dsl_impls.rs b/diesel/src/query_builder/select_statement/dsl_impls.rs
index b73338089da3..579f46426040 100644
--- a/diesel/src/query_builder/select_statement/dsl_impls.rs
+++ b/diesel/src/query_builder/select_statement/dsl_impls.rs
@@ -389,7 +389,7 @@ where
 impl<F, S, D, W, O, LOf, G, H, Expr> GroupByDsl<Expr> for SelectStatement<F, S, D, W, O, LOf, G, H>
 where
     SelectStatement<F, S, D, W, O, LOf, GroupByClause<Expr>, H>: SelectQuery,
-    Expr: Expression,
+    Expr: Expression + AppearsOnTable<F>,
 {
     type Output = SelectStatement<F, S, D, W, O, LOf, GroupByClause<Expr>, H>;
 
diff --git a/diesel/src/query_builder/upsert/on_conflict_clause.rs b/diesel/src/query_builder/upsert/on_conflict_clause.rs
index f8527348c47b..a154285cb340 100644
--- a/diesel/src/query_builder/upsert/on_conflict_clause.rs
+++ b/diesel/src/query_builder/upsert/on_conflict_clause.rs
@@ -9,9 +9,9 @@ use crate::result::QueryResult;
 #[doc(hidden)]
 #[derive(Debug, Clone, Copy)]
 pub struct OnConflictValues<Values, Target, Action> {
-    values: Values,
-    target: Target,
-    action: Action,
+    pub(crate) values: Values,
+    pub(crate) target: Target,
+    pub(crate) action: Action,
 }
 
 impl<Values, Target, Action> QueryId for OnConflictValues<Values, Target, Action> {
@@ -53,7 +53,7 @@ where
     DB: Backend,
     DB::OnConflictClause: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
     Values: QueryFragment<DB>,
-    Target: QueryFragment<DB>,
+    Target: QueryFragment<DB> + super::on_conflict_target_decorations::UndecoratedConflictTarget,
     Action: QueryFragment<DB>,
 {
     fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
@@ -64,3 +64,19 @@ where
         Ok(())
     }
 }
+
+impl<DB, Values, Target, Action, Where> QueryFragment<DB>
+    for OnConflictValues<
+        Values,
+        super::on_conflict_target_decorations::DecoratedConflictTarget<Target, Where>,
+        Action,
+    >
+where
+    DB: Backend,
+    DB::OnConflictClause: sql_dialect::on_conflict_clause::SupportsOnConflictClause,
+    Self: QueryFragment<DB, DB::OnConflictClause>,
+{
+    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
+        <Self as QueryFragment<DB, DB::OnConflictClause>>::walk_ast(self, pass)
+    }
+}
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 015abb203e35..1bd3d92eac61 100644
--- a/diesel/src/query_builder/upsert/on_conflict_target_decorations.rs
+++ b/diesel/src/query_builder/upsert/on_conflict_target_decorations.rs
@@ -1,8 +1,6 @@
-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};
-use crate::query_builder::{AstPass, QueryFragment, QueryResult};
 use crate::sql_types::BoolOrNullableBool;
 
 pub trait UndecoratedConflictTarget {}
@@ -56,13 +54,3 @@ where
         }
     }
 }
-
-impl<DB, T, U> QueryFragment<DB> for DecoratedConflictTarget<T, U>
-where
-    DB: Backend,
-    Self: QueryFragment<DB, DB::OnConflictClause>,
-{
-    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
-        <Self as QueryFragment<DB, DB::OnConflictClause>>::walk_ast(self, pass)
-    }
-}
diff --git a/diesel/src/query_dsl/group_by_dsl.rs b/diesel/src/query_dsl/group_by_dsl.rs
index 1c62c6885974..7a712b5af533 100644
--- a/diesel/src/query_dsl/group_by_dsl.rs
+++ b/diesel/src/query_dsl/group_by_dsl.rs
@@ -27,6 +27,7 @@ where
     T: Table + AsQuery<Query = SelectStatement<FromClause<T>>>,
     T::DefaultSelection: Expression<SqlType = T::SqlType> + ValidGrouping<()>,
     T::SqlType: TypedExpressionType,
+    T::Query: GroupByDsl<Expr>,
 {
     type Output = dsl::GroupBy<SelectStatement<FromClause<T>>, Expr>;
 
diff --git a/diesel/src/query_source/aliasing/aliased_field.rs b/diesel/src/query_source/aliasing/aliased_field.rs
index b8dc1c34b04f..1e5db2f8f625 100644
--- a/diesel/src/query_source/aliasing/aliased_field.rs
+++ b/diesel/src/query_source/aliasing/aliased_field.rs
@@ -77,10 +77,13 @@ where
 {
     type IsAggregate = is_aggregate::No;
 }
-impl<S, C> ValidGrouping<AliasedField<S, C>> for AliasedField<S, C>
+
+impl<S, C1, C2> ValidGrouping<AliasedField<S, C1>> for AliasedField<S, C2>
 where
     S: AliasSource,
-    C: Column<Table = S::Target>,
+    C1: Column<Table = S::Target>,
+    C2: Column<Table = S::Target>,
+    C2: ValidGrouping<C1, IsAggregate = is_aggregate::Yes>,
 {
     type IsAggregate = is_aggregate::Yes;
 }
diff --git a/diesel/src/query_source/aliasing/dsl_impls.rs b/diesel/src/query_source/aliasing/dsl_impls.rs
index 18669f7fea1f..80da92ecc9b3 100644
--- a/diesel/src/query_source/aliasing/dsl_impls.rs
+++ b/diesel/src/query_source/aliasing/dsl_impls.rs
@@ -194,6 +194,7 @@ where
     <Self as QuerySource>::DefaultSelection:
         Expression<SqlType = <Self as AsQuery>::SqlType> + ValidGrouping<()>,
     <Self as AsQuery>::SqlType: TypedExpressionType,
+    <Self as AsQuery>::Query: GroupByDsl<Expr>,
 {
     type Output = dsl::GroupBy<SelectStatement<FromClause<Self>>, Expr>;
 
diff --git a/diesel_bench/Cargo.toml b/diesel_bench/Cargo.toml
index 4dadf4ccdd9f..971f2b9a9565 100644
--- a/diesel_bench/Cargo.toml
+++ b/diesel_bench/Cargo.toml
@@ -22,7 +22,7 @@ quaint = {version = "=0.2.0-alpha.13", optional = true}
 serde = {version = "1", optional = true, features = ["derive"]}
 sea-orm = {version = "0.9", optional = true, features = ["runtime-tokio-rustls"]}
 futures = {version = "0.3", optional = true}
-#diesel-async = {git = "https://github.com/weiznich/diesel_async", rev = "3ab3cf8", optional = true, default-features = false}
+diesel-async = {version = "0.1", optional = true, default-features = false}
 criterion-perf-events = { version = "0.2", optional = true}
 perfcnt = {version = "0.8", optional = true}
 
@@ -55,4 +55,4 @@ fast_run = []
 
 [patch.crates-io]
 quaint = {git = "https://github.com/prisma/quaint", rev = "e077df3"}
-#diesel = { path = "../diesel"}
+diesel = {path = "../diesel"}
diff --git a/diesel_cli/Cargo.toml b/diesel_cli/Cargo.toml
index 5f8555d1d26b..75a01c5ca175 100644
--- a/diesel_cli/Cargo.toml
+++ b/diesel_cli/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "diesel_cli"
-version = "2.0.0"
+version = "2.0.1"
 license = "MIT OR Apache-2.0"
 description = "Provides the CLI for the Diesel crate"
 readme = "README.md"
@@ -26,9 +26,9 @@ dotenvy = "0.15"
 heck = "0.4.0"
 serde = { version = "1.0.0", features = ["derive"] }
 toml = "0.5"
-url = { version = "2.2.2", optional = true }
+url = { version = "2.2.2" }
 libsqlite3-sys = { version = ">=0.17.2, <0.26.0", optional = true }
-diffy = "0.2.0"
+diffy = "0.3.0"
 regex = "1.0.6"
 serde_regex = "1.1"
 
@@ -49,9 +49,9 @@ url = { version = "2.2.2" }
 
 [features]
 default = ["postgres", "sqlite", "mysql"]
-postgres = ["diesel/postgres", "url", "uses_information_schema"]
+postgres = ["diesel/postgres", "uses_information_schema"]
 sqlite = ["diesel/sqlite"]
-mysql = ["diesel/mysql", "url", "uses_information_schema"]
+mysql = ["diesel/mysql", "uses_information_schema"]
 sqlite-bundled = ["sqlite", "libsqlite3-sys/bundled"]
 uses_information_schema = []
 
diff --git a/diesel_cli/src/database.rs b/diesel_cli/src/database.rs
index c8f646328814..b921cb01d667 100644
--- a/diesel_cli/src/database.rs
+++ b/diesel_cli/src/database.rs
@@ -172,7 +172,8 @@ fn create_database_if_needed(database_url: &str) -> DatabaseResult<()> {
         }
         #[cfg(feature = "sqlite")]
         Backend::Sqlite => {
-            if !::std::path::Path::new(database_url).exists() {
+            let path = path_from_sqlite_url(database_url)?;
+            if !path.exists() {
                 println!("Creating database: {}", database_url);
                 SqliteConnection::establish(database_url)?;
             }
@@ -361,6 +362,30 @@ fn change_database_of_url(database_url: &str, default_database: &str) -> (String
     (database, new_url.into())
 }
 
+#[cfg(feature = "sqlite")]
+/// sqlite accepts either file: URLs, or bare paths (the latter of which may be relative).
+/// Check for which case we're in and return the path if we can retrieve it.
+fn path_from_sqlite_url(database_url: &str) -> DatabaseResult<::std::path::PathBuf> {
+    if database_url.starts_with("file:/") {
+        // looks like a file URL
+        match ::url::Url::parse(database_url) {
+            Ok(url) if url.scheme() == "file" => Ok(url.to_file_path().map_err(|_err| {
+                result::ConnectionError::InvalidConnectionUrl(String::from(database_url))
+            })?),
+            _ => {
+                // invalid URL or scheme
+                Err(
+                    result::ConnectionError::InvalidConnectionUrl(String::from(database_url))
+                        .into(),
+                )
+            }
+        }
+    } else {
+        // assume it's a bare path
+        Ok(::std::path::PathBuf::from(database_url))
+    }
+}
+
 fn handle_error<E: Error, T>(error: E) -> T {
     println!("{}", error);
     ::std::process::exit(1);
diff --git a/diesel_cli/src/infer_schema_internals/mysql.rs b/diesel_cli/src/infer_schema_internals/mysql.rs
index 233d8f1a6e5c..36167de37904 100644
--- a/diesel_cli/src/infer_schema_internals/mysql.rs
+++ b/diesel_cli/src/infer_schema_internals/mysql.rs
@@ -93,7 +93,7 @@ pub fn determine_column_type(
 
     Ok(ColumnType {
         schema: None,
-        sql_name: tpe.trim().to_lowercase(),
+        sql_name: tpe.trim().to_string(),
         rust_name: tpe.trim().to_upper_camel_case(),
         is_array: false,
         is_nullable: attr.nullable,
diff --git a/diesel_cli/src/infer_schema_internals/pg.rs b/diesel_cli/src/infer_schema_internals/pg.rs
index 9b2e1fdc2a30..065bcc99422b 100644
--- a/diesel_cli/src/infer_schema_internals/pg.rs
+++ b/diesel_cli/src/infer_schema_internals/pg.rs
@@ -38,7 +38,7 @@ pub fn determine_column_type(
                 Some(s.clone())
             }
         }),
-        sql_name: tpe.to_lowercase(),
+        sql_name: tpe.to_string(),
         rust_name: tpe.to_upper_camel_case(),
         is_array,
         is_nullable: attr.nullable,
diff --git a/diesel_derives/Cargo.toml b/diesel_derives/Cargo.toml
index dce07bc66453..258f21d2a921 100644
--- a/diesel_derives/Cargo.toml
+++ b/diesel_derives/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "diesel_derives"
-version = "2.0.0"
+version = "2.0.1"
 license = "MIT OR Apache-2.0"
 description = "You should not use this crate directly, it is internal to Diesel."
 documentation = "https://diesel.rs/guides/"
diff --git a/diesel_derives/src/insertable.rs b/diesel_derives/src/insertable.rs
index ac7e0d2b2a6d..0882d2dd0ec1 100644
--- a/diesel_derives/src/insertable.rs
+++ b/diesel_derives/src/insertable.rs
@@ -119,8 +119,10 @@ pub fn derive(item: DeriveInput) -> TokenStream {
         use diesel::internal::derives::insertable::UndecoratedInsertRecord;
         use diesel::prelude::*;
 
+        #[allow(unused_qualifications)]
         #insert_owned
 
+        #[allow(unused_qualifications)]
         #insert_borrowed
 
         impl #impl_generics UndecoratedInsertRecord<#table_name::table>
diff --git a/rust-toolchain b/rust-toolchain
index af92bdd9f58d..9405730420ff 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,1 +1,1 @@
-1.63.0
+1.64.0


Test patch:
diff --git a/diesel_cli/tests/print_schema.rs b/diesel_cli/tests/print_schema.rs
index 0f34ea388aac..904208ffc28a 100644
--- a/diesel_cli/tests/print_schema.rs
+++ b/diesel_cli/tests/print_schema.rs
@@ -229,6 +229,12 @@ fn print_schema_sqlite_implicit_foreign_key_reference() {
     test_print_schema("print_schema_sqlite_implicit_foreign_key_reference", vec![]);
 }
 
+#[test]
+#[cfg(feature = "postgres")]
+fn print_schema_respects_type_name_case() {
+    test_print_schema("print_schema_respects_type_name_case", vec!["--with-docs"])
+}
+
 #[cfg(feature = "sqlite")]
 const BACKEND: &str = "sqlite";
 #[cfg(feature = "postgres")]
diff --git a/diesel_cli/tests/print_schema/print_schema_respects_type_name_case/diesel.toml b/diesel_cli/tests/print_schema/print_schema_respects_type_name_case/diesel.toml
new file mode 100644
index 000000000000..750e5ba85830
--- /dev/null
+++ b/diesel_cli/tests/print_schema/print_schema_respects_type_name_case/diesel.toml
@@ -0,0 +1,3 @@
+[print_schema]
+file = "src/schema.rs"
+with_docs = true
diff --git a/diesel_cli/tests/print_schema/print_schema_respects_type_name_case/postgres/expected.rs b/diesel_cli/tests/print_schema/print_schema_respects_type_name_case/postgres/expected.rs
new file mode 100644
index 000000000000..e0c58fabfec8
--- /dev/null
+++ b/diesel_cli/tests/print_schema/print_schema_respects_type_name_case/postgres/expected.rs
@@ -0,0 +1,56 @@
+// @generated automatically by Diesel CLI.
+
+/// A module containing custom SQL type definitions
+///
+/// (Automatically generated by Diesel.)
+pub mod sql_types {
+    /// The `MyType` SQL type
+    ///
+    /// (Automatically generated by Diesel.)
+    #[derive(diesel::sql_types::SqlType)]
+    #[diesel(postgres_type(name = "MyType"))]
+    pub struct MyType;
+
+    /// The `MyType2` SQL type
+    ///
+    /// (Automatically generated by Diesel.)
+    #[derive(diesel::sql_types::SqlType)]
+    #[diesel(postgres_type(name = "MyType2"))]
+    pub struct MyType2;
+}
+
+diesel::table! {
+    use diesel::sql_types::*;
+    use super::sql_types::MyType;
+    use super::sql_types::MyType2;
+
+    /// Representation of the `custom_types` table.
+    ///
+    /// (Automatically generated by Diesel.)
+    custom_types (id) {
+        /// The `id` column of the `custom_types` table.
+        ///
+        /// Its SQL type is `Int4`.
+        ///
+        /// (Automatically generated by Diesel.)
+        id -> Int4,
+        /// The `custom_enum` column of the `custom_types` table.
+        ///
+        /// Its SQL type is `MyType`.
+        ///
+        /// (Automatically generated by Diesel.)
+        custom_enum -> MyType,
+        /// The `custom_enum_nullable` column of the `custom_types` table.
+        ///
+        /// Its SQL type is `Nullable<MyType>`.
+        ///
+        /// (Automatically generated by Diesel.)
+        custom_enum_nullable -> Nullable<MyType>,
+        /// The `custom_enum2` column of the `custom_types` table.
+        ///
+        /// Its SQL type is `MyType2`.
+        ///
+        /// (Automatically generated by Diesel.)
+        custom_enum2 -> MyType2,
+    }
+}
diff --git a/diesel_cli/tests/print_schema/print_schema_respects_type_name_case/postgres/schema.sql b/diesel_cli/tests/print_schema/print_schema_respects_type_name_case/postgres/schema.sql
new file mode 100644
index 000000000000..becbb2634e98
--- /dev/null
+++ b/diesel_cli/tests/print_schema/print_schema_respects_type_name_case/postgres/schema.sql
@@ -0,0 +1,8 @@
+CREATE TYPE "MyType" AS ENUM ('foo', 'bar');
+CREATE TYPE "MyType2" AS ENUM ('foo', 'bar');
+CREATE TABLE custom_types (
+    id SERIAL PRIMARY KEY,
+    custom_enum "MyType" NOT NULL,
+    custom_enum_nullable "MyType",
+    custom_enum2 "MyType2" NOT NULL
+);
diff --git a/diesel_compile_tests/Cargo.lock b/diesel_compile_tests/Cargo.lock
index 437070da3beb..0da3f61c940d 100644
--- a/diesel_compile_tests/Cargo.lock
+++ b/diesel_compile_tests/Cargo.lock
@@ -58,7 +58,7 @@ dependencies = [
 
 [[package]]
 name = "diesel"
-version = "2.0.0-rc.1"
+version = "2.0.0"
 dependencies = [
  "bigdecimal",
  "bitflags",
@@ -92,7 +92,7 @@ dependencies = [
 
 [[package]]
 name = "diesel_derives"
-version = "2.0.0-rc.1"
+version = "2.0.0"
 dependencies = [
  "proc-macro-error",
  "proc-macro2",
diff --git a/diesel_compile_tests/tests/fail/alias_and_group_by.rs b/diesel_compile_tests/tests/fail/alias_and_group_by.rs
new file mode 100644
index 000000000000..34b19eb562b1
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/alias_and_group_by.rs
@@ -0,0 +1,37 @@
+extern crate diesel;
+
+use diesel::alias;
+use diesel::prelude::*;
+
+table! {
+    users {
+        id -> Integer,
+        name -> VarChar,
+    }
+}
+
+fn main() {
+    let conn = &mut PgConnection::establish("…").unwrap();
+    let user_alias = alias!(users as user1);
+
+    // allowed as this groups by the the same field
+    user_alias
+        .group_by(user_alias.field(users::name))
+        .select(user_alias.field(users::name))
+        .execute(conn)
+        .unwrap();
+
+    // allowed as this groups by the primary key
+    user_alias
+        .group_by(user_alias.field(users::id))
+        .select(user_alias.field(users::name))
+        .execute(conn)
+        .unwrap();
+
+    // fails as this groups by an incompatible field
+    user_alias
+        .group_by(user_alias.field(users::name))
+        .select(user_alias.field(users::id))
+        .execute(conn)
+        .unwrap();
+}
diff --git a/diesel_compile_tests/tests/fail/alias_and_group_by.stderr b/diesel_compile_tests/tests/fail/alias_and_group_by.stderr
new file mode 100644
index 000000000000..dac75ea14e09
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/alias_and_group_by.stderr
@@ -0,0 +1,20 @@
+error[E0271]: type mismatch resolving `<columns::name as IsContainedInGroupBy<columns::id>>::Output == diesel::expression::is_contained_in_group_by::Yes`
+  --> tests/fail/alias_and_group_by.rs:34:10
+   |
+34 |         .select(user_alias.field(users::id))
+   |          ^^^^^^ expected struct `diesel::expression::is_contained_in_group_by::No`, found struct `diesel::expression::is_contained_in_group_by::Yes`
+   |
+note: required because of the requirements on the impl of `ValidGrouping<columns::name>` for `columns::id`
+  --> tests/fail/alias_and_group_by.rs:6:1
+   |
+6  | / table! {
+7  | |     users {
+8  | |         id -> Integer,
+9  | |         name -> VarChar,
+10 | |     }
+11 | | }
+   | |_^
+   = note: 1 redundant requirement hidden
+   = note: required because of the requirements on the impl of `ValidGrouping<AliasedField<user1, columns::name>>` for `AliasedField<user1, columns::id>`
+   = note: required because of the requirements on the impl of `SelectDsl<AliasedField<user1, columns::id>>` for `SelectStatement<FromClause<Alias<user1>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<Alias<user1>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<AliasedField<user1, columns::name>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` which comes from the expansion of the macro `table` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/diesel_compile_tests/tests/fail/invalid_group_by.rs b/diesel_compile_tests/tests/fail/invalid_group_by.rs
new file mode 100644
index 000000000000..212f5a3ddfdc
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/invalid_group_by.rs
@@ -0,0 +1,76 @@
+extern crate diesel;
+
+use diesel::alias;
+use diesel::prelude::*;
+
+table! {
+    users {
+        id -> Integer,
+        name -> VarChar,
+    }
+}
+
+table! {
+    posts {
+        id -> Integer,
+    }
+}
+
+allow_columns_to_appear_in_same_group_by_clause!(users::id, posts::id);
+
+fn main() {
+    let conn = &mut PgConnection::establish("..").unwrap();
+
+    // this fails because `posts` is not part of the from clause
+    users::table
+        .group_by(posts::id)
+        .select(users::id)
+        .execute(conn)
+        .unwrap();
+
+    // order of select and group by does not matter for the error
+    users::table
+        .select(users::id)
+        .group_by(posts::id)
+        .execute(conn)
+        .unwrap();
+
+    let (user_alias, post_alias) = alias!(users as user1, posts as post1,);
+
+    // this also fails if we use aliases
+    user_alias
+        .group_by(posts::id)
+        .select(user_alias.field(users::id))
+        .execute(conn)
+        .unwrap();
+
+    users::table
+        .group_by(post_alias.field(posts::id))
+        .select(users::id)
+        .execute(conn)
+        .unwrap();
+
+    user_alias
+        .group_by(post_alias.field(posts::id))
+        .select(user_alias.field(users::id))
+        .execute(conn)
+        .unwrap();
+
+    user_alias
+        .select(user_alias.field(users::id))
+        .group_by(posts::id)
+        .execute(conn)
+        .unwrap();
+
+    users::table
+        .select(users::id)
+        .group_by(post_alias.field(posts::id))
+        .execute(conn)
+        .unwrap();
+
+    user_alias
+        .select(user_alias.field(users::id))
+        .group_by(post_alias.field(posts::id))
+        .execute(conn)
+        .unwrap();
+}
diff --git a/diesel_compile_tests/tests/fail/invalid_group_by.stderr b/diesel_compile_tests/tests/fail/invalid_group_by.stderr
new file mode 100644
index 000000000000..edf358bf7777
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/invalid_group_by.stderr
@@ -0,0 +1,183 @@
+error[E0277]: the trait bound `FromClause<users::table>: AppearsInFromClause<posts::table>` is not satisfied
+  --> tests/fail/invalid_group_by.rs:26:10
+   |
+26 |         .group_by(posts::id)
+   |          ^^^^^^^^ the trait `AppearsInFromClause<posts::table>` is not implemented for `FromClause<users::table>`
+   |
+   = help: the trait `AppearsInFromClause<QS1>` is implemented for `FromClause<QS2>`
+note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `posts::columns::id`
+  --> tests/fail/invalid_group_by.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |     }
+17 | | }
+   | |_^
+   = note: required because of the requirements on the impl of `GroupByDsl<posts::columns::id>` for `SelectStatement<FromClause<users::table>>`
+   = note: this error originates in the macro `$crate::__diesel_column` which comes from the expansion of the macro `table` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0271]: type mismatch resolving `<posts::columns::id as IsContainedInGroupBy<users::columns::id>>::Output == diesel::expression::is_contained_in_group_by::Yes`
+  --> tests/fail/invalid_group_by.rs:27:10
+   |
+27 |         .select(users::id)
+   |          ^^^^^^ expected struct `diesel::expression::is_contained_in_group_by::No`, found struct `diesel::expression::is_contained_in_group_by::Yes`
+   |
+note: required because of the requirements on the impl of `ValidGrouping<posts::columns::id>` for `users::columns::id`
+  --> tests/fail/invalid_group_by.rs:6:1
+   |
+6  | / table! {
+7  | |     users {
+8  | |         id -> Integer,
+9  | |         name -> VarChar,
+10 | |     }
+11 | | }
+   | |_^
+   = note: required because of the requirements on the impl of `SelectDsl<users::columns::id>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<posts::columns::id>>`
+   = note: this error originates in the macro `$crate::__diesel_column` which comes from the expansion of the macro `table` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `FromClause<users::table>: AppearsInFromClause<posts::table>` is not satisfied
+  --> tests/fail/invalid_group_by.rs:34:10
+   |
+34 |         .group_by(posts::id)
+   |          ^^^^^^^^ the trait `AppearsInFromClause<posts::table>` is not implemented for `FromClause<users::table>`
+   |
+   = help: the trait `AppearsInFromClause<QS1>` is implemented for `FromClause<QS2>`
+note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `posts::columns::id`
+  --> tests/fail/invalid_group_by.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |     }
+17 | | }
+   | |_^
+   = note: required because of the requirements on the impl of `GroupByDsl<posts::columns::id>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<users::columns::id>>`
+   = note: this error originates in the macro `$crate::__diesel_column` which comes from the expansion of the macro `table` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `FromClause<Alias<user1>>: AppearsInFromClause<posts::table>` is not satisfied
+  --> tests/fail/invalid_group_by.rs:42:10
+   |
+42 |         .group_by(posts::id)
+   |          ^^^^^^^^ the trait `AppearsInFromClause<posts::table>` is not implemented for `FromClause<Alias<user1>>`
+   |
+   = help: the trait `AppearsInFromClause<QS1>` is implemented for `FromClause<QS2>`
+note: required because of the requirements on the impl of `AppearsOnTable<FromClause<Alias<user1>>>` for `posts::columns::id`
+  --> tests/fail/invalid_group_by.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |     }
+17 | | }
+   | |_^
+   = note: required because of the requirements on the impl of `GroupByDsl<posts::columns::id>` for `SelectStatement<FromClause<Alias<user1>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` which comes from the expansion of the macro `table` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `AliasedField<user1, users::columns::id>: ValidGrouping<posts::columns::id>` is not satisfied
+  --> tests/fail/invalid_group_by.rs:43:10
+   |
+43 |         .select(user_alias.field(users::id))
+   |          ^^^^^^ the trait `ValidGrouping<posts::columns::id>` is not implemented for `AliasedField<user1, users::columns::id>`
+   |
+   = help: the following other types implement trait `ValidGrouping<GroupByClause>`:
+             <AliasedField<S, C2> as ValidGrouping<AliasedField<S, C1>>>
+             <AliasedField<S, C> as ValidGrouping<()>>
+   = note: required because of the requirements on the impl of `SelectDsl<AliasedField<user1, users::columns::id>>` for `SelectStatement<FromClause<Alias<user1>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<Alias<user1>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<posts::columns::id>>`
+
+error[E0271]: type mismatch resolving `<FromClause<users::table> as AppearsInFromClause<Alias<post1>>>::Count == diesel::query_source::Once`
+  --> tests/fail/invalid_group_by.rs:48:10
+   |
+48 |         .group_by(post_alias.field(posts::id))
+   |          ^^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
+   |
+   = note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `AliasedField<post1, posts::columns::id>`
+   = note: required because of the requirements on the impl of `GroupByDsl<AliasedField<post1, posts::columns::id>>` for `SelectStatement<FromClause<users::table>>`
+
+error[E0277]: the trait bound `AliasedField<post1, posts::columns::id>: IsContainedInGroupBy<users::columns::id>` is not satisfied
+  --> tests/fail/invalid_group_by.rs:49:10
+   |
+49 |         .select(users::id)
+   |          ^^^^^^ the trait `IsContainedInGroupBy<users::columns::id>` is not implemented for `AliasedField<post1, posts::columns::id>`
+   |
+   = help: the following other types implement trait `IsContainedInGroupBy<T>`:
+             <(T0, T1) as IsContainedInGroupBy<Col>>
+             <(T0, T1, T2) as IsContainedInGroupBy<Col>>
+             <(T0, T1, T2, T3) as IsContainedInGroupBy<Col>>
+             <(T0, T1, T2, T3, T4) as IsContainedInGroupBy<Col>>
+             <(T0, T1, T2, T3, T4, T5) as IsContainedInGroupBy<Col>>
+             <(T0, T1, T2, T3, T4, T5, T6) as IsContainedInGroupBy<Col>>
+             <(T0, T1, T2, T3, T4, T5, T6, T7) as IsContainedInGroupBy<Col>>
+             <(T0, T1, T2, T3, T4, T5, T6, T7, T8) as IsContainedInGroupBy<Col>>
+           and 35 others
+note: required because of the requirements on the impl of `ValidGrouping<AliasedField<post1, posts::columns::id>>` for `users::columns::id`
+  --> tests/fail/invalid_group_by.rs:6:1
+   |
+6  | / table! {
+7  | |     users {
+8  | |         id -> Integer,
+9  | |         name -> VarChar,
+10 | |     }
+11 | | }
+   | |_^
+   = note: required because of the requirements on the impl of `SelectDsl<users::columns::id>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<AliasedField<post1, posts::columns::id>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` which comes from the expansion of the macro `table` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `FromClause<Alias<user1>>: AppearsInFromClause<Alias<post1>>` is not satisfied
+  --> tests/fail/invalid_group_by.rs:54:10
+   |
+54 |         .group_by(post_alias.field(posts::id))
+   |          ^^^^^^^^ the trait `AppearsInFromClause<Alias<post1>>` is not implemented for `FromClause<Alias<user1>>`
+   |
+   = help: the trait `AppearsInFromClause<QS1>` is implemented for `FromClause<QS2>`
+   = note: required because of the requirements on the impl of `AppearsOnTable<FromClause<Alias<user1>>>` for `AliasedField<post1, posts::columns::id>`
+   = note: required because of the requirements on the impl of `GroupByDsl<AliasedField<post1, posts::columns::id>>` for `SelectStatement<FromClause<Alias<user1>>>`
+
+error[E0277]: the trait bound `AliasedField<user1, users::columns::id>: ValidGrouping<AliasedField<post1, posts::columns::id>>` is not satisfied
+  --> tests/fail/invalid_group_by.rs:55:10
+   |
+55 |         .select(user_alias.field(users::id))
+   |          ^^^^^^ the trait `ValidGrouping<AliasedField<post1, posts::columns::id>>` is not implemented for `AliasedField<user1, users::columns::id>`
+   |
+   = help: the following other types implement trait `ValidGrouping<GroupByClause>`:
+             <AliasedField<S, C2> as ValidGrouping<AliasedField<S, C1>>>
+             <AliasedField<S, C> as ValidGrouping<()>>
+   = note: required because of the requirements on the impl of `SelectDsl<AliasedField<user1, users::columns::id>>` for `SelectStatement<FromClause<Alias<user1>>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<Alias<user1>>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_offset_clause::LimitOffsetClause<diesel::query_builder::limit_clause::NoLimitClause, diesel::query_builder::offset_clause::NoOffsetClause>, diesel::query_builder::group_by_clause::GroupByClause<AliasedField<post1, posts::columns::id>>>`
+
+error[E0277]: the trait bound `FromClause<Alias<user1>>: AppearsInFromClause<posts::table>` is not satisfied
+  --> tests/fail/invalid_group_by.rs:61:10
+   |
+61 |         .group_by(posts::id)
+   |          ^^^^^^^^ the trait `AppearsInFromClause<posts::table>` is not implemented for `FromClause<Alias<user1>>`
+   |
+   = help: the trait `AppearsInFromClause<QS1>` is implemented for `FromClause<QS2>`
+note: required because of the requirements on the impl of `AppearsOnTable<FromClause<Alias<user1>>>` for `posts::columns::id`
+  --> tests/fail/invalid_group_by.rs:13:1
+   |
+13 | / table! {
+14 | |     posts {
+15 | |         id -> Integer,
+16 | |     }
+17 | | }
+   | |_^
+   = note: required because of the requirements on the impl of `GroupByDsl<posts::columns::id>` for `SelectStatement<FromClause<Alias<user1>>, diesel::query_builder::select_clause::SelectClause<AliasedField<user1, users::columns::id>>>`
+   = note: this error originates in the macro `$crate::__diesel_column` which comes from the expansion of the macro `table` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0271]: type mismatch resolving `<FromClause<users::table> as AppearsInFromClause<Alias<post1>>>::Count == diesel::query_source::Once`
+  --> tests/fail/invalid_group_by.rs:67:10
+   |
+67 |         .group_by(post_alias.field(posts::id))
+   |          ^^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once`
+   |
+   = note: required because of the requirements on the impl of `AppearsOnTable<FromClause<users::table>>` for `AliasedField<post1, posts::columns::id>`
+   = note: required because of the requirements on the impl of `GroupByDsl<AliasedField<post1, posts::columns::id>>` for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::SelectClause<users::columns::id>>`
+
+error[E0277]: the trait bound `FromClause<Alias<user1>>: AppearsInFromClause<Alias<post1>>` is not satisfied
+  --> tests/fail/invalid_group_by.rs:73:10
+   |
+73 |         .group_by(post_alias.field(posts::id))
+   |          ^^^^^^^^ the trait `AppearsInFromClause<Alias<post1>>` is not implemented for `FromClause<Alias<user1>>`
+   |
+   = help: the trait `AppearsInFromClause<QS1>` is implemented for `FromClause<QS2>`
+   = note: required because of the requirements on the impl of `AppearsOnTable<FromClause<Alias<user1>>>` for `AliasedField<post1, posts::columns::id>`
+   = note: required because of the requirements on the impl of `GroupByDsl<AliasedField<post1, posts::columns::id>>` for `SelectStatement<FromClause<Alias<user1>>, diesel::query_builder::select_clause::SelectClause<AliasedField<user1, users::columns::id>>>`
diff --git a/diesel_compile_tests/tests/fail/invalid_upsert.rs b/diesel_compile_tests/tests/fail/invalid_upsert.rs
new file mode 100644
index 000000000000..5c8b36bd4f42
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/invalid_upsert.rs
@@ -0,0 +1,35 @@
+extern crate diesel;
+
+use diesel::prelude::*;
+
+table! {
+    users {
+        id -> Integer,
+        name -> Text,
+        hair_color -> Nullable<Text>,
+    }
+}
+
+fn main() {
+    let conn = &mut PgConnection::establish("...").unwrap();
+
+    // this query is valid
+    diesel::insert_into(users::table)
+        .values(&[(users::id.eq(1), users::name.eq("Sean"))])
+        .on_conflict(users::id)
+        .filter_target(users::hair_color.eq("black"))
+        .do_update()
+        .set(users::hair_color.eq("red"))
+        .execute(conn)
+        .unwrap();
+
+    // This is invalid as filter_target is only valid for
+    // do update queries
+    diesel::insert_into(users::table)
+        .values(&[(users::id.eq(1), users::name.eq("Sean"))])
+        .on_conflict(users::id)
+        .filter_target(users::hair_color.eq("black"))
+        .do_nothing()
+        .execute(conn)
+        .unwrap();
+}
diff --git a/diesel_compile_tests/tests/fail/invalid_upsert.stderr b/diesel_compile_tests/tests/fail/invalid_upsert.stderr
new file mode 100644
index 000000000000..12ce92e5d8a7
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/invalid_upsert.stderr
@@ -0,0 +1,16 @@
+error[E0275]: overflow evaluating the requirement `_: Sized`
+    --> tests/fail/invalid_upsert.rs:33:10
+     |
+33   |         .execute(conn)
+     |          ^^^^^^^
+     |
+     = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`$CRATE`)
+     = note: required because of the requirements on the impl of `QueryFragment<_>` for `diesel::query_builder::upsert::on_conflict_clause::OnConflictValues<diesel::query_builder::insert_statement::batch_insert::BatchInsert<Vec<diesel::query_builder::insert_statement::ValuesClause<(ColumnInsertValue<columns::id, &diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>, ColumnInsertValue<columns::name, &diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>), users::table>>, users::table, [diesel::query_builder::insert_statement::ValuesClause<(ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>, ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>), users::table>; 1], true>, diesel::query_builder::upsert::on_conflict_target_decorations::DecoratedConflictTarget<diesel::query_builder::upsert::on_conflict_target::ConflictTarget<columns::id>, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<columns::hair_color, diesel::expression::bound::Bound<diesel::sql_types::Nullable<diesel::sql_types::Text>, &str>>>>>, diesel::query_builder::upsert::on_conflict_actions::DoNothing>`
+     = note: 127 redundant requirements hidden
+     = note: required because of the requirements on the impl of `QueryFragment<_>` for `InsertStatement<users::table, diesel::query_builder::upsert::on_conflict_clause::OnConflictValues<diesel::query_builder::insert_statement::batch_insert::BatchInsert<Vec<diesel::query_builder::insert_statement::ValuesClause<(ColumnInsertValue<columns::id, &diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>, ColumnInsertValue<columns::name, &diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>), users::table>>, users::table, [diesel::query_builder::insert_statement::ValuesClause<(ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>, ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>), users::table>; 1], true>, diesel::query_builder::upsert::on_conflict_target_decorations::DecoratedConflictTarget<diesel::query_builder::upsert::on_conflict_target::ConflictTarget<columns::id>, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<columns::hair_color, diesel::expression::bound::Bound<diesel::sql_types::Nullable<diesel::sql_types::Text>, &str>>>>>, diesel::query_builder::upsert::on_conflict_actions::DoNothing>>`
+     = note: required because of the requirements on the impl of `ExecuteDsl<_, _>` for `InsertStatement<users::table, diesel::query_builder::upsert::on_conflict_clause::OnConflictValues<diesel::query_builder::insert_statement::batch_insert::BatchInsert<Vec<diesel::query_builder::insert_statement::ValuesClause<(ColumnInsertValue<columns::id, &diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>, ColumnInsertValue<columns::name, &diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>), users::table>>, users::table, [diesel::query_builder::insert_statement::ValuesClause<(ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>, ColumnInsertValue<columns::name, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>), users::table>; 1], true>, diesel::query_builder::upsert::on_conflict_target_decorations::DecoratedConflictTarget<diesel::query_builder::upsert::on_conflict_target::ConflictTarget<columns::id>, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<columns::hair_color, diesel::expression::bound::Bound<diesel::sql_types::Nullable<diesel::sql_types::Text>, &str>>>>>, diesel::query_builder::upsert::on_conflict_actions::DoNothing>>`
+note: required by a bound in `diesel::RunQueryDsl::execute`
+    --> $DIESEL/src/query_dsl/mod.rs
+     |
+     |         Self: methods::ExecuteDsl<Conn>,
+     |               ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::RunQueryDsl::execute`
diff --git a/diesel_compile_tests/tests/fail/subselect_requires_correct_type.stderr b/diesel_compile_tests/tests/fail/subselect_requires_correct_type.stderr
index 1a89f130fa80..09bd3ca41623 100644
--- a/diesel_compile_tests/tests/fail/subselect_requires_correct_type.stderr
+++ b/diesel_compile_tests/tests/fail/subselect_requires_correct_type.stderr
@@ -1,14 +1,14 @@
 error[E0277]: the trait bound `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>>: diesel::expression::array_comparison::AsInExpression<diesel::sql_types::Integer>` is not satisfied
-  --> tests/fail/subselect_requires_correct_type.rs:22:59
-   |
-22 |     let query = posts::table.filter(posts::user_id.eq_any(subquery));
-   |                                                    ------ ^^^^^^^^ the trait `diesel::expression::array_comparison::AsInExpression<diesel::sql_types::Integer>` is not implemented for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>>`
-   |                                                    |
-   |                                                    required by a bound introduced by this call
-   |
-   = help: the trait `diesel::expression::array_comparison::AsInExpression<ST>` is implemented for `SelectStatement<F, S, D, W, O, LOf, G, H, LC>`
+   --> tests/fail/subselect_requires_correct_type.rs:22:59
+    |
+22  |     let query = posts::table.filter(posts::user_id.eq_any(subquery));
+    |                                                    ------ ^^^^^^^^ the trait `diesel::expression::array_comparison::AsInExpression<diesel::sql_types::Integer>` is not implemented for `SelectStatement<FromClause<users::table>, diesel::query_builder::select_clause::DefaultSelectClause<FromClause<users::table>>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<users::columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>>>`
+    |                                                    |
+    |                                                    required by a bound introduced by this call
+    |
+    = help: the trait `diesel::expression::array_comparison::AsInExpression<ST>` is implemented for `SelectStatement<F, S, D, W, O, LOf, G, H, LC>`
 note: required by a bound in `eq_any`
-  --> $DIESEL/src/expression_methods/global_expression_methods.rs
-   |
-   |         T: AsInExpression<Self::SqlType>,
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `eq_any`
+   --> $DIESEL/src/expression_methods/global_expression_methods.rs
+    |
+    |         T: AsInExpression<Self::SqlType>,
+    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `eq_any`
diff --git a/diesel_tests/tests/alias.rs b/diesel_tests/tests/alias.rs
index a8bea87853b4..d78582c46e03 100644
--- a/diesel_tests/tests/alias.rs
+++ b/diesel_tests/tests/alias.rs
@@ -173,3 +173,21 @@ fn visibility() {
         const USERS_ALIAS_2: Alias<UsersAlias2> = users as users_alias_2;
     }
 }
+
+// regression test for
+// https://github.com/diesel-rs/diesel/issues/3319
+#[test]
+fn aliasing_with_group_by_and_primary_key() {
+    let connection = &mut connection_with_sean_and_tess_in_users_table();
+    let user_alias = alias!(users as user1);
+
+    let res = user_alias
+        .group_by(user_alias.field(users::id))
+        .select(user_alias.field(users::name))
+        .order_by(user_alias.field(users::id))
+        .load::<String>(connection)
+        .unwrap();
+    assert!(res.len() == 2);
+    assert_eq!(res[0], "Sean");
+    assert_eq!(res[1], "Tess");
+}
diff --git a/diesel_tests/tests/connection.rs b/diesel_tests/tests/connection.rs
index 9625bd94b362..954818b5fbfe 100644
--- a/diesel_tests/tests/connection.rs
+++ b/diesel_tests/tests/connection.rs
@@ -2,22 +2,23 @@ use crate::schema::*;
 use diesel::connection::BoxableConnection;
 use diesel::*;
 
-table! {
-    auto_time {
-        id -> Integer,
-        n -> Integer,
-        updated_at -> Timestamp,
-    }
-}
-
 #[test]
 #[cfg(any(feature = "postgres", feature = "sqlite"))]
 fn managing_updated_at_for_table() {
-    use self::auto_time::dsl::*;
     use crate::schema_dsl::*;
     use chrono::NaiveDateTime;
     use std::{thread, time::Duration};
 
+    table! {
+        #[sql_name = "auto_time"]
+            auto_time_table {
+            id -> Integer,
+            n -> Integer,
+            updated_at -> Timestamp,
+        }
+    }
+    use auto_time_table::dsl::{auto_time_table as auto_time, n, updated_at};
+
     // transactions have frozen time, so we can't use them
     let connection = &mut connection_without_transaction();
     create_table(
@@ -116,3 +117,77 @@ fn boxable_connection_downcast_mut_usable() {
 
     assert_eq!(Ok(String::from("Sean")), sean);
 }
+
+#[test]
+#[cfg(feature = "postgres")]
+fn use_the_same_connection_multiple_times() {
+    use crate::*;
+    use diesel::result::DatabaseErrorKind;
+    use diesel::result::Error::DatabaseError;
+
+    table! {
+        #[sql_name = "github_issue_3342"]
+        github_issue_3342_table {
+            id -> Serial,
+            uid -> Integer,
+        }
+    }
+    use github_issue_3342_table::dsl::{github_issue_3342_table as github_issue_3342, uid};
+
+    let connection = &mut connection_without_transaction();
+
+    // We can extend `schema_dsl` module to accommodate UNIQUE constraint.
+    sql_query(
+        r#"
+          CREATE TABLE github_issue_3342 (
+            id SERIAL PRIMARY KEY,
+            uid INTEGER NOT NULL UNIQUE
+          )
+        "#,
+    )
+    .execute(connection)
+    .unwrap();
+
+    let mut _drop_conn = connection_without_transaction();
+    let _guard = DropTable {
+        connection: &mut _drop_conn,
+        table_name: "github_issue_3342",
+        can_drop: true,
+    };
+
+    // helper method to simulate database error.
+    fn insert_or_fetch(conn: &mut PgConnection, input: i32) {
+        let result = insert_into(github_issue_3342)
+            .values(uid.eq(input))
+            .get_result::<(i32, i32)>(conn);
+
+        match result {
+            Ok((_, r)) => assert_eq!(r, input),
+            Err(DatabaseError(DatabaseErrorKind::UniqueViolation, _)) => {
+                let result = github_issue_3342
+                    .filter(uid.eq(input))
+                    .first::<(i32, i32)>(conn);
+                match result {
+                    Ok((_, r)) => assert_eq!(r, input),
+                    Err(DatabaseError(DatabaseErrorKind::UnableToSendCommand, message))
+                        if message.message() == "another command is already in progress\n" =>
+                    {
+                        panic!("The fix didn't solve the problem!?")
+                    }
+                    Err(e) => panic!("Caused by: {}", e),
+                }
+            }
+            Err(DatabaseError(DatabaseErrorKind::UnableToSendCommand, message))
+                if message.message() == "another command is already in progress\n" =>
+            {
+                panic!("The fix didn't solve the problem!?")
+            }
+            Err(e) => panic!("Caused by: {}", e),
+        }
+    }
+
+    // simulate multiple queries using the same connection sequentially.
+    for _ in 0..5 {
+        insert_or_fetch(connection, 1);
+    }
+}
diff --git a/diesel_tests/tests/debug/mod.rs b/diesel_tests/tests/debug/mod.rs
index 50e822f8c928..a57a303b5403 100644
--- a/diesel_tests/tests/debug/mod.rs
+++ b/diesel_tests/tests/debug/mod.rs
@@ -149,13 +149,14 @@ fn test_upsert() {
         .values(&values)
         .on_conflict(hair_color)
         .filter_target(hair_color.eq("black"))
-        .do_nothing();
+        .do_update()
+        .set(hair_color.eq("red"));
     let upsert_single_where_sql_display =
         debug_query::<TestBackend, _>(&upsert_command_single_where).to_string();
 
     assert_eq!(
         upsert_single_where_sql_display,
-        r#"INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) ON CONFLICT ("hair_color") WHERE ("users"."hair_color" = $5) DO NOTHING -- binds: ["Sean", Some("black"), "Tess", None, "black"]"#
+        r#"INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) ON CONFLICT ("hair_color") DO UPDATE SET "hair_color" = $5 WHERE ("users"."hair_color" = $6) -- binds: ["Sean", Some("black"), "Tess", None, "red", "black"]"#
     );
 
     let upsert_command_second_where = insert_into(users)
@@ -163,13 +164,14 @@ fn test_upsert() {
         .on_conflict(hair_color)
         .filter_target(hair_color.eq("black"))
         .filter_target(name.eq("Sean"))
-        .do_nothing();
+        .do_update()
+        .set(hair_color.eq("red"));
 
     let upsert_second_where_sql_display =
         debug_query::<TestBackend, _>(&upsert_command_second_where).to_string();
 
     assert_eq!(
         upsert_second_where_sql_display,
-        r#"INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) ON CONFLICT ("hair_color") WHERE (("users"."hair_color" = $5) AND ("users"."name" = $6)) DO NOTHING -- binds: ["Sean", Some("black"), "Tess", None, "black", "Sean"]"#
+        r#"INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) ON CONFLICT ("hair_color") DO UPDATE SET "hair_color" = $5 WHERE (("users"."hair_color" = $6) AND ("users"."name" = $7)) -- binds: ["Sean", Some("black"), "Tess", None, "red", "black", "Sean"]"#
     );
 }
diff --git a/diesel_tests/tests/update.rs b/diesel_tests/tests/update.rs
index 229ae6130c0d..30ac16c42959 100644
--- a/diesel_tests/tests/update.rs
+++ b/diesel_tests/tests/update.rs
@@ -308,6 +308,50 @@ fn upsert_with_sql_literal_for_target() {
     assert_eq!(Ok(expected_data), data);
 }
 
+// regression test for https://github.com/diesel-rs/diesel/issues/3330
+#[test]
+#[cfg(feature = "postgres")]
+fn upsert_with_target_filter() {
+    #[derive(AsChangeset)]
+    #[diesel(table_name = users)]
+    struct Changes<'a> {
+        hair_color: Option<&'a str>,
+    }
+
+    let conn = &mut connection_with_sean_and_tess_in_users_table();
+
+    let users = [User::new(1, "Sean"), User::new(2, "Tess")];
+    let query = insert_into(users::table)
+        .values(&users)
+        .on_conflict(users::id)
+        .filter_target(users::name.eq("Sean"))
+        .do_update()
+        .set(&Changes {
+            hair_color: Some("red"),
+        });
+
+    let upsert_single_where_sql_display = debug_query::<TestBackend, _>(&query).to_string();
+
+    assert_eq!(
+        upsert_single_where_sql_display,
+        r#"INSERT INTO "users" ("id", "name", "hair_color") VALUES ($1, $2, DEFAULT), ($3, $4, DEFAULT) ON CONFLICT ("id") DO UPDATE SET "hair_color" = $5 WHERE ("users"."name" = $6) -- binds: [1, "Sean", 2, "Tess", "red", "Sean"]"#
+    );
+
+    let result = query.execute(conn);
+
+    assert_eq!(result, Ok(1));
+    let users = users::table
+        .order_by(users::id)
+        .load::<(i32, String, Option<String>)>(conn)
+        .unwrap();
+
+    assert_eq!(
+        users[0],
+        (1, String::from("Sean"), Some(String::from("red")))
+    );
+    assert_eq!(users[1], (2, String::from("Tess"), None));
+}
+
 #[test]
 #[cfg(feature = "postgres")]
 fn update_array_index_expression() {