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

Issue:
Compile Error: assertion `left == right` failed: Unexpected output from mysql_config: `-L/usr/local/mysql/lib -lmysqlclient -lssl -lcrypto -lresolv`
<!--
If you want to report a bug, we added some points below which help us track down the problem faster.
-->

## Setup

### Versions

- **Rust:*1.72*
- **Diesel:*2.2.0*
- **Database:*MySQL*
- **Operating System*MacOS 12*

### Feature Flags

- **diesel:** ["mysql", "chrono", "r2d2"]

## Problem Description
I've been using diesel for awhile with no issue. Recently I started getting this compilation error and all efforts to troubleshoot have failed, including downgrading to previous versions. This is the error:

```bash
--- stderr
  thread 'main' panicked at /Users/prodbyola/.cargo/registry/src/index.crates.io-6f17d22bba15001f/mysqlclient-sys-0.3.1/build.rs:59:9:
  assertion `left == right` failed: Unexpected output from mysql_config: `-L/usr/local/mysql/lib -lmysqlclient -lssl -lcrypto -lresolv`
    left: 5
   right: 2
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

I also tried moving my project to Windows (WSL) to be sure it's not platform-specific issue. But I got very similar error. I'm not sure how to fix this please.

### What are you trying to accomplish?


### What is the expected output?


### What is the actual output?


### Are you seeing any additional errors?


### Steps to reproduce

<!--
Please include as much of your codebase as needed to reproduce the error.  If the relevant files are large, please consider linking to a public repository or a [Gist](https://gist.github.com/). This includes normally the following parts:

* The exact code where your hit the problem
* Relevant parts your schema, so any `table!` macro calls required for
* Any other type definitions involved in the code, which produces your problem
-->

## Checklist

- [ ] I have already looked over the [issue tracker](https://github.com/diesel-rs/diesel/issues) and the [discussion forum](https://github.com/diesel-rs/diesel/discussions) for similar possible closed issues.
<!--
If you are unsure if your issue is a duplicate of an existing issue please link the issue in question here
--> 
- [ ] This issue can be reproduced on Rust's stable channel. (Your issue will be
  closed if this is not the case)
- [ ] This issue can be reproduced without requiring a third party crate

<!--
Thank you for your submission!  You're helping make Diesel more robust 🎉

We'll try to respond as quickly as possible.
-->



Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a8183b1e4b0d..aaf3b9a8a5c9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,11 +10,22 @@ Increasing the minimal supported Rust version will always be coupled at least wi
 
 ## Unreleased
 
+## [2.2.1] 2024-06-12
+
+## Fixed
+
+* Fixed using `#[dsl::auto_type]` with functions that accept reference arguments
+* Fixed using `#[derive(Queryable)]` with structs that use a type named `Row` as field type
+* Fixed a regression that prevented using `mysqlclient-sys` 0.2.x with diesel 2.2
+* Fixed connecting to postgres database using the scram-sha-256 authentication method on windows while using the bundled postgres builds
+* Improved the error messages in diesel-cli for cases where a file/folder was not found
+* Fixed several version detection bugs in mysqlclient-sys to use pre-generated bindings in more situations
+
 ## [2.2.0] 2024-05-31
 
 ### Added
 
-* Support `[print_schema] exclude_custom_type_definitions = ["Vector"]`. If a `custom type` matches one element on the list it's skipped.
+* Support `[print_schema] except_custom_type_definitions = ["Vector"]`. If a `custom type` matches one element on the list it's skipped.
 * Added automatic usage of all sqlite `rowid` aliases when no explicit primary key is defined for `print-schema`
 * Added a `#[dsl::auto_type]` attribute macro, allowing to infer type of query fragment functions
 * Added the same type inference on `Selectable` derives, which allows skipping specifying `select_expression_type` most of the time, in turn enabling most queries to be written using just a `Selectable` derive.
diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml
index 5d3e15368861..a421ca403327 100644
--- a/diesel/Cargo.toml
+++ b/diesel/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "diesel"
-version = "2.2.0"
+version = "2.2.1"
 license = "MIT OR Apache-2.0"
 description = "A safe, extensible ORM and Query Builder for PostgreSQL, SQLite, and MySQL"
 readme = "README.md"
@@ -25,10 +25,10 @@ byteorder = { version = "1.0", optional = true }
 chrono = { version = "0.4.20", optional = true, default-features = false, features = ["clock", "std"] }
 libc = { version = "0.2.0", optional = true }
 libsqlite3-sys = { version = ">=0.17.2, <0.29.0", optional = true, features = ["bundled_bindings"] }
-mysqlclient-sys = { version = ">=0.2.5, <0.4.0",  optional = true }
+mysqlclient-sys = { version = ">=0.2.5, <0.5.0",  optional = true }
 mysqlclient-src = { version = "0.1.0", optional = true }
 pq-sys = { version = ">=0.4.0, <0.7.0", optional = true }
-pq-src = { version = "0.2", optional = true }
+pq-src = { version = "0.3", optional = true }
 quickcheck = { version = "1.0.3", optional = true }
 serde_json = { version = ">=0.8.0, <2.0", optional = true }
 url = { version = "2.1.0", optional = true }
diff --git a/diesel/src/mysql/connection/bind.rs b/diesel/src/mysql/connection/bind.rs
index 3b85c7665351..3aed940799bd 100644
--- a/diesel/src/mysql/connection/bind.rs
+++ b/diesel/src/mysql/connection/bind.rs
@@ -389,13 +389,13 @@ impl BindData {
             length,
             capacity,
             flags,
-            is_null: ffi::FALSE,
-            is_truncated: Some(ffi::FALSE),
+            is_null: super::raw::ffi_false(),
+            is_truncated: Some(super::raw::ffi_false()),
         }
     }
 
     fn is_truncated(&self) -> bool {
-        self.is_truncated.unwrap_or(ffi::FALSE) != ffi::FALSE
+        self.is_truncated.unwrap_or(super::raw::ffi_false()) != super::raw::ffi_false()
     }
 
     fn is_fixed_size_buffer(&self) -> bool {
@@ -711,7 +711,9 @@ impl From<(ffi::enum_field_types, Flags)> for MysqlType {
                  something has gone wrong. Please open an issue at \
                  the diesel github repo."
             ),
-
+            // depending on the bindings version
+            // there might be no unlisted field type
+            #[allow(unreachable_patterns)]
             t => unreachable!(
                 "Unsupported type encountered: {t:?}. \
                  If you ever see this error, something has gone wrong. \
diff --git a/diesel/src/mysql/connection/raw.rs b/diesel/src/mysql/connection/raw.rs
index f73f2b815454..dbd08866a22e 100644
--- a/diesel/src/mysql/connection/raw.rs
+++ b/diesel/src/mysql/connection/raw.rs
@@ -11,6 +11,19 @@ use crate::result::{ConnectionError, ConnectionResult, QueryResult};
 
 pub(super) struct RawConnection(NonNull<ffi::MYSQL>);
 
+// old versions of mysqlclient do not expose
+// ffi::FALSE, so we need to have our own compatibility
+// wrapper here
+//
+// Depending on the bindings version ffi::my_bool
+// might be an actual bool or a i8. For the former
+// case `default()` corresponds to `false` for the later
+// to `0` which is both interpreted as false
+#[inline(always)]
+pub(super) fn ffi_false() -> ffi::my_bool {
+    Default::default()
+}
+
 impl RawConnection {
     pub(super) fn new() -> Self {
         perform_thread_unsafe_library_initialization();
@@ -175,7 +188,7 @@ impl RawConnection {
     }
 
     fn more_results(&self) -> bool {
-        unsafe { ffi::mysql_more_results(self.0.as_ptr()) != ffi::FALSE }
+        unsafe { ffi::mysql_more_results(self.0.as_ptr()) != ffi_false() }
     }
 
     fn next_result(&self) -> QueryResult<()> {
diff --git a/diesel_cli/Cargo.toml b/diesel_cli/Cargo.toml
index 78dc0e541436..dde0f0a94d35 100644
--- a/diesel_cli/Cargo.toml
+++ b/diesel_cli/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "diesel_cli"
-version = "2.2.0"
+version = "2.2.1"
 license = "MIT OR Apache-2.0"
 description = "Provides the CLI for the Diesel crate"
 readme = "README.md"
@@ -47,7 +47,7 @@ url = { version = "2.2.2" }
 libsqlite3-sys = { version = ">=0.17.2, <0.29.0", optional = true }
 pq-sys = { version = ">=0.4, <0.7.0", optional = true }
 openssl-sys = { version = "0.9.93", features = ["vendored"], optional = true }
-mysqlclient-sys = { version = ">=0.2.5, <0.4.0", optional = true }
+mysqlclient-sys = { version = "0.4.0", optional = true }
 diffy = "0.3.0"
 regex = "1.0.6"
 serde_regex = "1.1"
diff --git a/diesel_cli/src/config.rs b/diesel_cli/src/config.rs
index 346d0288bf23..fb3fca7502fe 100644
--- a/diesel_cli/src/config.rs
+++ b/diesel_cli/src/config.rs
@@ -56,7 +56,8 @@ impl Config {
         let path = Self::file_path(matches);
 
         if path.exists() {
-            let content = fs::read_to_string(&path)?;
+            let content = fs::read_to_string(&path)
+                .map_err(|e| crate::errors::Error::IoError(e, Some(path.to_owned())))?;
             let mut result = toml::from_str::<Self>(&content)?;
             result.set_relative_path_base(
                 path.parent()
diff --git a/diesel_cli/src/database.rs b/diesel_cli/src/database.rs
index 6657cabd56b6..0b5b5090b64f 100644
--- a/diesel_cli/src/database.rs
+++ b/diesel_cli/src/database.rs
@@ -9,9 +9,7 @@ use diesel_migrations::FileBasedMigrations;
 
 use std::env;
 #[cfg(feature = "postgres")]
-use std::fs::{self, File};
-#[cfg(feature = "postgres")]
-use std::io::Write;
+use std::fs::{self};
 use std::path::Path;
 
 #[derive(Copy, Clone, Eq, PartialEq)]
@@ -242,11 +240,21 @@ fn create_default_migration_if_needed(
     match Backend::for_url(database_url) {
         #[cfg(feature = "postgres")]
         Backend::Pg => {
-            fs::create_dir_all(&initial_migration_path)?;
-            let mut up_sql = File::create(initial_migration_path.join("up.sql"))?;
-            up_sql.write_all(include_bytes!("setup_sql/postgres/initial_setup/up.sql"))?;
-            let mut down_sql = File::create(initial_migration_path.join("down.sql"))?;
-            down_sql.write_all(include_bytes!("setup_sql/postgres/initial_setup/down.sql"))?;
+            fs::create_dir_all(&initial_migration_path).map_err(|e| {
+                crate::errors::Error::IoError(e, Some(initial_migration_path.clone()))
+            })?;
+            let up_sql_file = initial_migration_path.join("up.sql");
+            std::fs::write(
+                &up_sql_file,
+                include_bytes!("setup_sql/postgres/initial_setup/up.sql"),
+            )
+            .map_err(|e| crate::errors::Error::IoError(e, Some(up_sql_file.clone())))?;
+            let down_sql_file = initial_migration_path.join("down.sql");
+            std::fs::write(
+                &down_sql_file,
+                include_bytes!("setup_sql/postgres/initial_setup/down.sql"),
+            )
+            .map_err(|e| crate::errors::Error::IoError(e, Some(down_sql_file.clone())))?;
         }
         _ => {} // No default migration for this backend
     }
@@ -296,7 +304,9 @@ fn drop_database(database_url: &str) -> Result<(), crate::errors::Error> {
         Backend::Sqlite => {
             if Path::new(database_url).exists() {
                 println!("Dropping database: {database_url}");
-                std::fs::remove_file(database_url)?;
+                std::fs::remove_file(database_url).map_err(|e| {
+                    crate::errors::Error::IoError(e, Some(std::path::PathBuf::from(database_url)))
+                })?;
             }
         }
         #[cfg(feature = "mysql")]
diff --git a/diesel_cli/src/errors.rs b/diesel_cli/src/errors.rs
index 4d6d48cd38e3..6c079e8a3176 100644
--- a/diesel_cli/src/errors.rs
+++ b/diesel_cli/src/errors.rs
@@ -18,8 +18,8 @@ pub enum Error {
     ProjectRootNotFound(PathBuf),
     #[error("The --database-url argument must be passed, or the DATABASE_URL environment variable must be set.")]
     DatabaseUrlMissing,
-    #[error("Encountered an IO error: {0}")]
-    IoError(#[from] std::io::Error),
+    #[error("Encountered an IO error: {0} {}", print_optional_path(.1))]
+    IoError(#[source] std::io::Error, Option<PathBuf>),
     #[error("Failed to execute a database query: {0}")]
     QueryError(#[from] diesel::result::Error),
     #[error("Failed to run migrations: {0}")]
@@ -63,3 +63,9 @@ pub enum Error {
     #[error("No `[print_schema.{0}]` entries in your diesel.toml")]
     NoSchemaKeyFound(String),
 }
+
+fn print_optional_path(path: &Option<PathBuf>) -> String {
+    path.as_ref()
+        .map(|p| format!(" for `{}`", p.display()))
+        .unwrap_or_default()
+}
diff --git a/diesel_cli/src/main.rs b/diesel_cli/src/main.rs
index 778fe92e3ca1..77767ae06bbc 100644
--- a/diesel_cli/src/main.rs
+++ b/diesel_cli/src/main.rs
@@ -150,8 +150,10 @@ fn create_config_file(
             "dir = \"migrations\"",
             &format!("dir = \"{}\"", migrations_dir_toml_string),
         );
-        let mut file = fs::File::create(path)?;
-        file.write_all(modified_content.as_bytes())?;
+        let mut file = fs::File::create(&path)
+            .map_err(|e| crate::errors::Error::IoError(e, Some(path.to_owned())))?;
+        file.write_all(modified_content.as_bytes())
+            .map_err(|e| crate::errors::Error::IoError(e, Some(path.to_owned())))?;
     }
 
     Ok(())
@@ -193,13 +195,15 @@ fn generate_completions_command(matches: &ArgMatches) {
 /// Returns a `DatabaseError::ProjectRootNotFound` if no Cargo.toml is found.
 fn create_migrations_directory(path: &Path) -> Result<PathBuf, crate::errors::Error> {
     println!("Creating migrations directory at: {}", path.display());
-    fs::create_dir_all(path)?;
-    fs::File::create(path.join(".keep"))?;
+    fs::create_dir_all(path)
+        .map_err(|e| crate::errors::Error::IoError(e, Some(path.to_owned())))?;
+    let keep_path = path.join(".keep");
+    fs::File::create(&keep_path).map_err(|e| crate::errors::Error::IoError(e, Some(keep_path)))?;
     Ok(path.to_owned())
 }
 
 fn find_project_root() -> Result<PathBuf, crate::errors::Error> {
-    let current_dir = env::current_dir()?;
+    let current_dir = env::current_dir().map_err(|e| crate::errors::Error::IoError(e, None))?;
     search_for_directory_containing_file(&current_dir, "diesel.toml")
         .or_else(|_| search_for_directory_containing_file(&current_dir, "Cargo.toml"))
 }
@@ -260,8 +264,6 @@ fn run_infer_schema(matches: &ArgMatches) -> Result<(), crate::errors::Error> {
 
 #[tracing::instrument]
 fn regenerate_schema_if_file_specified(matches: &ArgMatches) -> Result<(), crate::errors::Error> {
-    use std::io::Read;
-
     tracing::debug!("Regenerate schema if required");
 
     let config = Config::read(matches)?.print_schema;
@@ -269,16 +271,16 @@ fn regenerate_schema_if_file_specified(matches: &ArgMatches) -> Result<(), crate
         if let Some(ref path) = config.file {
             let mut connection = InferConnection::from_matches(matches)?;
             if let Some(parent) = path.parent() {
-                fs::create_dir_all(parent)?;
+                fs::create_dir_all(parent)
+                    .map_err(|e| crate::errors::Error::IoError(e, Some(parent.to_owned())))?;
             }
 
             if matches.get_flag("LOCKED_SCHEMA") {
                 let mut buf = Vec::new();
                 print_schema::run_print_schema(&mut connection, config, &mut buf)?;
 
-                let mut old_buf = Vec::new();
-                let mut file = fs::File::open(path)?;
-                file.read_to_end(&mut old_buf)?;
+                let old_buf = std::fs::read(path)
+                    .map_err(|e| crate::errors::Error::IoError(e, Some(path.to_owned())))?;
 
                 if buf != old_buf {
                     return Err(crate::errors::Error::SchemaWouldChange(
@@ -286,11 +288,9 @@ fn regenerate_schema_if_file_specified(matches: &ArgMatches) -> Result<(), crate
                     ));
                 }
             } else {
-                use std::io::Write;
-
-                let mut file = fs::File::create(path)?;
                 let schema = print_schema::output_schema(&mut connection, config)?;
-                file.write_all(schema.as_bytes())?;
+                std::fs::write(path, schema.as_bytes())
+                    .map_err(|e| crate::errors::Error::IoError(e, Some(path.to_owned())))?;
             }
         }
     }
diff --git a/diesel_cli/src/migrations/diff_schema.rs b/diesel_cli/src/migrations/diff_schema.rs
index 08bce704fb07..113c73fdcc8c 100644
--- a/diesel_cli/src/migrations/diff_schema.rs
+++ b/diesel_cli/src/migrations/diff_schema.rs
@@ -4,8 +4,6 @@ use diesel::query_builder::QueryBuilder;
 use diesel::QueryResult;
 use diesel_table_macro_syntax::{ColumnDef, TableDecl};
 use std::collections::HashMap;
-use std::fs::File;
-use std::io::Read;
 use std::path::Path;
 use syn::visit::Visit;
 
@@ -37,9 +35,9 @@ pub fn generate_sql_based_on_diff_schema(
     let project_root = crate::find_project_root()?;
 
     let schema_path = project_root.join(schema_file_path);
-    let mut schema_file = File::open(schema_path)?;
-    let mut content = String::new();
-    schema_file.read_to_string(&mut content)?;
+    let content = std::fs::read_to_string(&schema_path)
+        .map_err(|e| crate::errors::Error::IoError(e, Some(schema_path.clone())))?;
+
     let syn_file = syn::parse_file(&content)?;
 
     let mut tables_from_schema = SchemaCollector::default();
diff --git a/diesel_cli/src/migrations/mod.rs b/diesel_cli/src/migrations/mod.rs
index 8ed0810ca923..754043824802 100644
--- a/diesel_cli/src/migrations/mod.rs
+++ b/diesel_cli/src/migrations/mod.rs
@@ -130,7 +130,8 @@ pub(super) fn run_migration_command(matches: &ArgMatches) -> Result<(), crate::e
             let version = migration_version(args);
             let versioned_name = format!("{version}_{migration_name}");
             let migration_dir = migrations_dir(matches)?.join(versioned_name);
-            fs::create_dir(&migration_dir)?;
+            fs::create_dir(&migration_dir)
+                .map_err(|e| crate::errors::Error::IoError(e, Some(migration_dir.clone())))?;
 
             match args
                 .get_one::<String>("MIGRATION_FORMAT")
@@ -164,17 +165,22 @@ fn generate_sql_migration(
 ) -> Result<(), crate::errors::Error> {
     use std::io::Write;
 
-    let migration_dir_relative =
-        crate::convert_absolute_path_to_relative(path, &env::current_dir()?);
+    let migration_dir_relative = crate::convert_absolute_path_to_relative(
+        path,
+        &env::current_dir().map_err(|e| crate::errors::Error::IoError(e, None))?,
+    );
 
     let up_path = path.join("up.sql");
     println!(
         "Creating {}",
         migration_dir_relative.join("up.sql").display()
     );
-    let mut up = fs::File::create(up_path)?;
-    up.write_all(b"-- Your SQL goes here\n")?;
-    up.write_all(up_sql.as_bytes())?;
+    let mut up = fs::File::create(&up_path)
+        .map_err(|e| crate::errors::Error::IoError(e, Some(up_path.clone())))?;
+    up.write_all(b"-- Your SQL goes here\n")
+        .map_err(|e| crate::errors::Error::IoError(e, Some(up_path.clone())))?;
+    up.write_all(up_sql.as_bytes())
+        .map_err(|e| crate::errors::Error::IoError(e, Some(up_path.clone())))?;
 
     if with_down {
         let down_path = path.join("down.sql");
@@ -182,9 +188,12 @@ fn generate_sql_migration(
             "Creating {}",
             migration_dir_relative.join("down.sql").display()
         );
-        let mut down = fs::File::create(down_path)?;
-        down.write_all(b"-- This file should undo anything in `up.sql`\n")?;
-        down.write_all(down_sql.as_bytes())?;
+        let mut down = fs::File::create(&down_path)
+            .map_err(|e| crate::errors::Error::IoError(e, Some(down_path.clone())))?;
+        down.write_all(b"-- This file should undo anything in `up.sql`\n")
+            .map_err(|e| crate::errors::Error::IoError(e, Some(up_path.clone())))?;
+        down.write_all(down_sql.as_bytes())
+            .map_err(|e| crate::errors::Error::IoError(e, Some(up_path.clone())))?;
     }
     Ok(())
 }
diff --git a/diesel_cli/src/print_schema.rs b/diesel_cli/src/print_schema.rs
index 1905f7c15e04..d5b1d6e4a024 100644
--- a/diesel_cli/src/print_schema.rs
+++ b/diesel_cli/src/print_schema.rs
@@ -48,7 +48,9 @@ pub fn run_print_schema<W: IoWrite>(
 ) -> Result<(), crate::errors::Error> {
     let schema = output_schema(connection, config)?;
 
-    output.write_all(schema.as_bytes())?;
+    output
+        .write_all(schema.as_bytes())
+        .map_err(|e| crate::errors::Error::IoError(e, None))?;
     Ok(())
 }
 
@@ -272,7 +274,7 @@ pub fn output_schema(
                     patch_file.display(),
                     e
                 );
-                return Err(e.into());
+                return Err(crate::errors::Error::IoError(e, Some(patch_file.clone())));
             }
         };
         let patch = diffy::Patch::from_str(&patch)?;
diff --git a/diesel_derives/Cargo.toml b/diesel_derives/Cargo.toml
index a5dc4e4a30aa..76e9f9dc554e 100644
--- a/diesel_derives/Cargo.toml
+++ b/diesel_derives/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "diesel_derives"
-version = "2.2.0"
+version = "2.2.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/queryable.rs b/diesel_derives/src/queryable.rs
index ac421365e8a4..72903241dedf 100644
--- a/diesel_derives/src/queryable.rs
+++ b/diesel_derives/src/queryable.rs
@@ -46,7 +46,7 @@ pub fn derive(item: DeriveInput) -> Result<TokenStream> {
 
     Ok(wrap_in_dummy_mod(quote! {
         use diesel::deserialize::{self, FromStaticSqlRow, Queryable};
-        use diesel::row::{Row, Field};
+        use diesel::row::{Row as _, Field as _};
         use std::convert::TryInto;
 
         impl #impl_generics Queryable<(#(#sql_type,)*), __DB> for #struct_name #ty_generics
diff --git a/dsl_auto_type/Cargo.toml b/dsl_auto_type/Cargo.toml
index 1a5358f2a5c7..e34246a5ce0b 100644
--- a/dsl_auto_type/Cargo.toml
+++ b/dsl_auto_type/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "dsl_auto_type"
-version = "0.1.0"
+version = "0.1.1"
 license = "MIT OR Apache-2.0"
 description = "Automatically expand query fragment types for factoring as functions"
 documentation = "https://docs.rs/crate/diesel_migrations"
@@ -15,7 +15,7 @@ either = "1"
 heck = "0.5"
 proc-macro2 = "1"
 quote = "1"
-syn = { version = "2", features = ["extra-traits", "full", "derive", "parsing"] }
+syn = { version = "2", features = ["extra-traits", "full", "derive", "parsing", "visit"] }
 
 [dev-dependencies]
 diesel = { path = "../diesel" }
diff --git a/dsl_auto_type/src/auto_type/expression_type_inference.rs b/dsl_auto_type/src/auto_type/expression_type_inference.rs
index 834030ec46e7..72dfb7f335ae 100644
--- a/dsl_auto_type/src/auto_type/expression_type_inference.rs
+++ b/dsl_auto_type/src/auto_type/expression_type_inference.rs
@@ -73,10 +73,12 @@ impl TypeInferrer<'_> {
             Err(e) => self.register_error(e, expr.span()),
         }
     }
+
     fn register_error(&self, error: syn::Error, infer_type_span: Span) -> syn::Type {
         self.errors.borrow_mut().push(Rc::new(error));
         parse_quote_spanned!(infer_type_span=> _)
     }
+
     fn try_infer_expression_type(
         &self,
         expr: &syn::Expr,
diff --git a/dsl_auto_type/src/auto_type/local_variables_map.rs b/dsl_auto_type/src/auto_type/local_variables_map.rs
index b8168f971f95..f008e2352569 100644
--- a/dsl_auto_type/src/auto_type/local_variables_map.rs
+++ b/dsl_auto_type/src/auto_type/local_variables_map.rs
@@ -116,6 +116,16 @@ impl<'a, 'p> LocalVariablesMap<'a, 'p> {
         Ok(())
     }
 
+    pub(crate) fn process_const_generic(&mut self, const_generic: &'a syn::ConstParam) {
+        self.inner.map.insert(
+            &const_generic.ident,
+            LetStatementInferredType {
+                type_: const_generic.ty.clone(),
+                errors: Vec::new(),
+            },
+        );
+    }
+
     /// Finishes a block inference for this map.
     /// It may be initialized with `pat`s before (such as function parameters),
     /// then this function is used to infer the type of the last expression in the block.
diff --git a/dsl_auto_type/src/auto_type/mod.rs b/dsl_auto_type/src/auto_type/mod.rs
index 58f9d4ab6700..0cc8a20384cb 100644
--- a/dsl_auto_type/src/auto_type/mod.rs
+++ b/dsl_auto_type/src/auto_type/mod.rs
@@ -1,6 +1,7 @@
 mod case;
 pub mod expression_type_inference;
 mod local_variables_map;
+mod referenced_generics;
 mod settings_builder;
 
 use {
@@ -134,6 +135,9 @@ pub(crate) fn auto_type_impl(
                     parent: None,
                 },
             };
+            for const_generic in input_function.sig.generics.const_params() {
+                local_variables_map.process_const_generic(const_generic);
+            }
             for function_param in &input_function.sig.inputs {
                 if let syn::FnArg::Typed(syn::PatType { pat, ty, .. }) = function_param {
                     match local_variables_map.process_pat(pat, Some(ty), None) {
@@ -165,11 +169,19 @@ pub(crate) fn auto_type_impl(
 
     let type_alias = match type_alias {
         Some(type_alias) => {
+            // We're generating a type alias so we need to extract the necessary lifetimes and
+            // generic type parameters for that type alias
+            let type_alias_generics = referenced_generics::extract_referenced_generics(
+                &return_type,
+                &input_function.sig.generics,
+                &mut errors,
+            );
+
             let vis = &input_function.vis;
-            input_function.sig.output = parse_quote!(-> #type_alias);
+            input_function.sig.output = parse_quote!(-> #type_alias #type_alias_generics);
             quote! {
                 #[allow(non_camel_case_types)]
-                #vis type #type_alias = #return_type;
+                #vis type #type_alias #type_alias_generics = #return_type;
             }
         }
         None => {
@@ -180,12 +192,13 @@ pub(crate) fn auto_type_impl(
 
     let mut res = quote! {
         #type_alias
+        #[allow(clippy::needless_lifetimes)]
         #input_function
     };
 
     for error in errors {
         // Extracting from the `Rc` only if it's the last reference is an elegant way to
-        // deduplicate errors For this to work it is necessary that the rest of
+        // deduplicate errors. For this to work it is necessary that the rest of
         // the errors (those from the local variables map that weren't used) are
         // dropped before, which is the case here, and that we are iterating on the
         // errors in an owned manner.
diff --git a/dsl_auto_type/src/auto_type/referenced_generics.rs b/dsl_auto_type/src/auto_type/referenced_generics.rs
new file mode 100644
index 000000000000..025ab11ea069
--- /dev/null
+++ b/dsl_auto_type/src/auto_type/referenced_generics.rs
@@ -0,0 +1,109 @@
+use std::rc::Rc;
+use syn::parse_quote;
+use syn::visit::{self, Visit};
+use syn::{Ident, Lifetime};
+
+pub(crate) fn extract_referenced_generics(
+    ty: &syn::Type,
+    generics: &syn::Generics,
+    errors: &mut Vec<Rc<syn::Error>>,
+) -> syn::Generics {
+    struct Visitor<'g, 'errs> {
+        lifetimes: Vec<(&'g Lifetime, bool)>,
+        type_parameters: Vec<(&'g Ident, bool)>,
+        errors: &'errs mut Vec<Rc<syn::Error>>,
+    }
+
+    let mut visitor = Visitor {
+        lifetimes: generics
+            .lifetimes()
+            .map(|lt| (&lt.lifetime, false))
+            .collect(),
+        type_parameters: generics
+            .type_params()
+            .map(|tp| (&tp.ident, false))
+            .collect(),
+        errors,
+    };
+    visitor.lifetimes.sort_unstable();
+    visitor.type_parameters.sort_unstable();
+
+    impl<'ast> Visit<'ast> for Visitor<'_, '_> {
+        fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
+            if lifetime.ident == "_" {
+                self.errors.push(Rc::new(syn::Error::new_spanned(
+                    lifetime,
+                    "`#[auto_type]` requires named lifetimes",
+                )));
+            } else if lifetime.ident != "static" {
+                if let Ok(lifetime_idx) = self
+                    .lifetimes
+                    .binary_search_by_key(&lifetime, |(lt, _)| *lt)
+                {
+                    self.lifetimes[lifetime_idx].1 = true;
+                }
+            }
+            visit::visit_lifetime(self, lifetime)
+        }
+
+        fn visit_type_reference(&mut self, reference: &'ast syn::TypeReference) {
+            if reference.lifetime.is_none() {
+                self.errors.push(Rc::new(syn::Error::new_spanned(
+                    reference,
+                    "`#[auto_type]` requires named lifetimes",
+                )));
+            }
+            visit::visit_type_reference(self, reference)
+        }
+
+        fn visit_type_path(&mut self, type_path: &'ast syn::TypePath) {
+            if let Some(path_ident) = type_path.path.get_ident() {
+                if let Ok(type_param_idx) = self
+                    .type_parameters
+                    .binary_search_by_key(&path_ident, |tp| tp.0)
+                {
+                    self.type_parameters[type_param_idx].1 = true;
+                }
+            }
+            visit::visit_type_path(self, type_path)
+        }
+    }
+
+    visitor.visit_type(ty);
+
+    let generic_params: syn::punctuated::Punctuated<syn::GenericParam, _> = generics
+        .params
+        .iter()
+        .filter_map(|param| match param {
+            syn::GenericParam::Lifetime(lt)
+                if visitor
+                    .lifetimes
+                    .binary_search(&(&lt.lifetime, true))
+                    .is_ok() =>
+            {
+                let lt = &lt.lifetime;
+                Some(parse_quote!(#lt))
+            }
+            syn::GenericParam::Type(tp)
+                if visitor
+                    .type_parameters
+                    .binary_search(&(&tp.ident, true))
+                    .is_ok() =>
+            {
+                let ident = &tp.ident;
+                Some(parse_quote!(#ident))
+            }
+            _ => None::<syn::GenericParam>,
+        })
+        .collect();
+
+    // We need to not set the lt_token and gt_token if `params` is empty to get
+    // a reasonable error message for the case that there is no lifetime specifier
+    // but we need one
+    syn::Generics {
+        lt_token: (!generic_params.is_empty()).then(Default::default),
+        gt_token: (!generic_params.is_empty()).then(Default::default),
+        params: generic_params,
+        where_clause: None,
+    }
+}


Test patch:
diff --git a/diesel_compile_tests/tests/fail/auto_type_life_times.rs b/diesel_compile_tests/tests/fail/auto_type_life_times.rs
new file mode 100644
index 000000000000..d20e68910e5a
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/auto_type_life_times.rs
@@ -0,0 +1,23 @@
+use diesel::dsl::*;
+use diesel::prelude::*;
+
+diesel::table! {
+    users {
+        id -> Integer,
+        name -> Text,
+    }
+}
+
+#[auto_type]
+fn with_lifetime(name: &'_ str) -> _ {
+    users::table.filter(users::name.eq(name))
+}
+
+#[auto_type]
+fn with_lifetime2(name: &str) -> _ {
+    users::table.filter(users::name.eq(name))
+}
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/diesel_compile_tests/tests/fail/auto_type_life_times.stderr b/diesel_compile_tests/tests/fail/auto_type_life_times.stderr
new file mode 100644
index 000000000000..4dcf2632d83a
--- /dev/null
+++ b/diesel_compile_tests/tests/fail/auto_type_life_times.stderr
@@ -0,0 +1,49 @@
+error: `#[auto_type]` requires named lifetimes
+  --> tests/fail/auto_type_life_times.rs:12:25
+   |
+12 | fn with_lifetime(name: &'_ str) -> _ {
+   |                         ^^
+
+error: `#[auto_type]` requires named lifetimes
+  --> tests/fail/auto_type_life_times.rs:17:25
+   |
+17 | fn with_lifetime2(name: &str) -> _ {
+   |                         ^^^^
+
+error[E0106]: missing lifetime specifier
+  --> tests/fail/auto_type_life_times.rs:12:25
+   |
+12 | fn with_lifetime(name: &'_ str) -> _ {
+   |                         ^^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+12 | fn with_lifetime<'a>(name: &'a str) -> _ {
+   |                 ++++        ~~
+
+error[E0106]: missing lifetime specifier
+  --> tests/fail/auto_type_life_times.rs:17:25
+   |
+17 | fn with_lifetime2(name: &str) -> _ {
+   |                         ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+17 | fn with_lifetime2<'a>(name: &'a str) -> _ {
+   |                  ++++        ++
+
+error: lifetime may not live long enough
+  --> tests/fail/auto_type_life_times.rs:13:5
+   |
+12 | fn with_lifetime(name: &'_ str) -> _ {
+   |                        - let's call the lifetime of this reference `'1`
+13 |     users::table.filter(users::name.eq(name))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> tests/fail/auto_type_life_times.rs:18:5
+   |
+17 | fn with_lifetime2(name: &str) -> _ {
+   |                         - let's call the lifetime of this reference `'1`
+18 |     users::table.filter(users::name.eq(name))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
diff --git a/diesel_derives/tests/auto_type.rs b/diesel_derives/tests/auto_type.rs
index f01face4aab7..614e6c482b23 100644
--- a/diesel_derives/tests/auto_type.rs
+++ b/diesel_derives/tests/auto_type.rs
@@ -355,6 +355,24 @@ fn test_normal_functions() -> _ {
     ))
 }
 
+#[auto_type]
+fn with_lifetime<'a>(name: &'a str) -> _ {
+    users::table.filter(users::name.eq(name))
+}
+
+#[auto_type]
+fn with_type_generics<'a, T>(name: &'a T) -> _
+where
+    &'a T: diesel::expression::AsExpression<diesel::sql_types::Text>,
+{
+    users::name.eq(name)
+}
+
+#[auto_type]
+fn with_const_generics<const N: i32>() -> _ {
+    users::id.eq(N)
+}
+
 // #[auto_type]
 // fn test_sql_fragment() -> _ {
 //     sql("foo")
diff --git a/diesel_derives/tests/queryable.rs b/diesel_derives/tests/queryable.rs
index f2b11713b992..3c17d2ecc107 100644
--- a/diesel_derives/tests/queryable.rs
+++ b/diesel_derives/tests/queryable.rs
@@ -87,3 +87,16 @@ fn multiple_tables() {
         data
     );
 }
+
+#[test]
+fn name_conflict() {
+    type Field = i32;
+    type Record = i32;
+
+    #[derive(Debug, Clone, PartialEq, Eq, Queryable)]
+    struct MyStruct(Field, Record);
+
+    let conn = &mut connection();
+    let data = select(sql::<(Integer, Integer)>("1, 2")).get_result(conn);
+    assert_eq!(Ok(MyStruct(1, 2)), data);
+}
diff --git a/diesel_tests/Cargo.toml b/diesel_tests/Cargo.toml
index 512d6d712100..5e113286de25 100644
--- a/diesel_tests/Cargo.toml
+++ b/diesel_tests/Cargo.toml
@@ -23,8 +23,8 @@ bigdecimal = ">= 0.0.13, < 0.5.0"
 rand = "0.8.4"
 libsqlite3-sys = { version = "0.28", optional = true }
 pq-sys = { version = "0.6", optional = true }
-pq-src = { version = "0.2", optional = true }
-mysqlclient-sys = { version = "0.3", optional = true }
+pq-src = { version = "0.3", optional = true }
+mysqlclient-sys = { version = "0.4", optional = true }
 mysqlclient-src = { version = "0.1.0", optional = true }
 
 [features]