From 9b56c2210250285478973ff8232270f502cf3ea1 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Wed, 27 Nov 2024 18:35:37 -0800 Subject: [PATCH 1/3] chore(raw_sql): create regression test --- tests/sqlite/sqlite.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/sqlite/sqlite.rs b/tests/sqlite/sqlite.rs index 24d84a9bb8..8f8f269580 100644 --- a/tests/sqlite/sqlite.rs +++ b/tests/sqlite/sqlite.rs @@ -8,6 +8,7 @@ use sqlx::{ }; use sqlx_sqlite::LockedSqliteHandle; use sqlx_test::new; +use std::future::Future; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -969,6 +970,24 @@ async fn test_multiple_set_rollback_hook_calls_drop_old_handler() -> anyhow::Res Ok(()) } +#[sqlx_macros::test] +async fn issue_3150() { + // Same bounds as `tokio::spawn()` + async fn fake_spawn(future: F) -> F::Output + where + F: Future + Send + 'static, + { + future.await + } + + fake_spawn(async { + let mut db = SqliteConnection::connect(":memory:").await.unwrap(); + sqlx::raw_sql("").execute(&mut db).await.unwrap(); + db.close().await.unwrap(); + }) + .await; +} + #[cfg(feature = "sqlite-preupdate-hook")] #[sqlx_macros::test] async fn test_query_with_preupdate_hook_insert() -> anyhow::Result<()> { From 8e078831faa01d1835844a3e985c4a7e03fbd44b Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Mon, 25 Nov 2024 16:04:17 -0800 Subject: [PATCH 2/3] fix: `RawSql` lifetime issues --- sqlx-core/src/raw_sql.rs | 54 +++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/sqlx-core/src/raw_sql.rs b/sqlx-core/src/raw_sql.rs index 37627d4453..b16361c39c 100644 --- a/sqlx-core/src/raw_sql.rs +++ b/sqlx-core/src/raw_sql.rs @@ -1,4 +1,5 @@ use either::Either; +use futures_core::future::BoxFuture; use futures_core::stream::BoxStream; use crate::database::Database; @@ -139,26 +140,28 @@ impl<'q, DB: Database> Execute<'q, DB> for RawSql<'q> { impl<'q> RawSql<'q> { /// Execute the SQL string and return the total number of rows affected. #[inline] - pub async fn execute<'e, E>( + pub async fn execute<'e, 'c: 'e, E, DB>( self, executor: E, - ) -> crate::Result<::QueryResult> + ) -> crate::Result where 'q: 'e, - E: Executor<'e>, + DB: Database, + E: Executor<'c, Database = DB>, { executor.execute(self).await } /// Execute the SQL string. Returns a stream which gives the number of rows affected for each statement in the string. #[inline] - pub fn execute_many<'e, E>( + pub fn execute_many<'e, 'c: 'e, E, DB>( self, executor: E, - ) -> BoxStream<'e, crate::Result<::QueryResult>> + ) -> BoxStream<'e, crate::Result> where 'q: 'e, - E: Executor<'e>, + DB: Database, + E: Executor<'c, Database = DB>, { executor.execute_many(self) } @@ -167,13 +170,14 @@ impl<'q> RawSql<'q> { /// /// If the string contains multiple statements, their results will be concatenated together. #[inline] - pub fn fetch<'e, E>( + pub fn fetch<'e, 'c: 'e, E, DB>( self, executor: E, - ) -> BoxStream<'e, Result<::Row, Error>> + ) -> BoxStream<'e, Result> where 'q: 'e, - E: Executor<'e>, + DB: Database, + E: Executor<'c, Database = DB>, { executor.fetch(self) } @@ -183,19 +187,20 @@ impl<'q> RawSql<'q> { /// For each query in the stream, any generated rows are returned first, /// then the `QueryResult` with the number of rows affected. #[inline] - pub fn fetch_many<'e, E>( + pub fn fetch_many<'e, 'c: 'e, E, DB>( self, executor: E, ) -> BoxStream< 'e, Result< - Either<::QueryResult, ::Row>, + Either, Error, >, > where 'q: 'e, - E: Executor<'e>, + DB: Database, + E: Executor<'c, Database = DB>, { executor.fetch_many(self) } @@ -208,15 +213,16 @@ impl<'q> RawSql<'q> { /// To avoid exhausting available memory, ensure the result set has a known upper bound, /// e.g. using `LIMIT`. #[inline] - pub async fn fetch_all<'e, E>( + pub fn fetch_all<'e, 'c: 'e, E, DB>( self, executor: E, - ) -> crate::Result::Row>> + ) -> BoxFuture<'e, crate::Result>> where 'q: 'e, - E: Executor<'e>, + DB: Database, + E: Executor<'c, Database = DB>, { - executor.fetch_all(self).await + executor.fetch_all(self) } /// Execute the SQL string, returning the first row or [`Error::RowNotFound`] otherwise. @@ -232,15 +238,16 @@ impl<'q> RawSql<'q> { /// /// Otherwise, you might want to add `LIMIT 1` to your query. #[inline] - pub async fn fetch_one<'e, E>( + pub fn fetch_one<'e, 'c: 'e, E, DB>( self, executor: E, - ) -> crate::Result<::Row> + ) -> BoxFuture<'e, crate::Result> where 'q: 'e, - E: Executor<'e>, + DB: Database, + E: Executor<'c, Database = DB>, { - executor.fetch_one(self).await + executor.fetch_one(self) } /// Execute the SQL string, returning the first row or [`None`] otherwise. @@ -256,13 +263,14 @@ impl<'q> RawSql<'q> { /// /// Otherwise, you might want to add `LIMIT 1` to your query. #[inline] - pub async fn fetch_optional<'e, E>( + pub async fn fetch_optional<'e, 'c: 'e, E, DB>( self, executor: E, - ) -> crate::Result<::Row> + ) -> crate::Result where 'q: 'e, - E: Executor<'e>, + DB: Database, + E: Executor<'c, Database = DB>, { executor.fetch_one(self).await } From 3a0f916da3bdf0708e35b1b0009f725dc597e010 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Wed, 27 Nov 2024 18:09:09 -0800 Subject: [PATCH 3/3] chore(raw_sql): try not adding another lifetime param --- sqlx-core/src/raw_sql.rs | 51 ++++++++++++---------------------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/sqlx-core/src/raw_sql.rs b/sqlx-core/src/raw_sql.rs index b16361c39c..f4104348bc 100644 --- a/sqlx-core/src/raw_sql.rs +++ b/sqlx-core/src/raw_sql.rs @@ -140,28 +140,25 @@ impl<'q, DB: Database> Execute<'q, DB> for RawSql<'q> { impl<'q> RawSql<'q> { /// Execute the SQL string and return the total number of rows affected. #[inline] - pub async fn execute<'e, 'c: 'e, E, DB>( - self, - executor: E, - ) -> crate::Result + pub async fn execute<'e, E, DB>(self, executor: E) -> crate::Result where 'q: 'e, DB: Database, - E: Executor<'c, Database = DB>, + E: Executor<'e, Database = DB>, { executor.execute(self).await } /// Execute the SQL string. Returns a stream which gives the number of rows affected for each statement in the string. #[inline] - pub fn execute_many<'e, 'c: 'e, E, DB>( + pub fn execute_many<'e, E, DB>( self, executor: E, ) -> BoxStream<'e, crate::Result> where 'q: 'e, DB: Database, - E: Executor<'c, Database = DB>, + E: Executor<'e, Database = DB>, { executor.execute_many(self) } @@ -170,14 +167,11 @@ impl<'q> RawSql<'q> { /// /// If the string contains multiple statements, their results will be concatenated together. #[inline] - pub fn fetch<'e, 'c: 'e, E, DB>( - self, - executor: E, - ) -> BoxStream<'e, Result> + pub fn fetch<'e, E, DB>(self, executor: E) -> BoxStream<'e, Result> where 'q: 'e, DB: Database, - E: Executor<'c, Database = DB>, + E: Executor<'e, Database = DB>, { executor.fetch(self) } @@ -187,20 +181,14 @@ impl<'q> RawSql<'q> { /// For each query in the stream, any generated rows are returned first, /// then the `QueryResult` with the number of rows affected. #[inline] - pub fn fetch_many<'e, 'c: 'e, E, DB>( + pub fn fetch_many<'e, E, DB>( self, executor: E, - ) -> BoxStream< - 'e, - Result< - Either, - Error, - >, - > + ) -> BoxStream<'e, Result, Error>> where 'q: 'e, DB: Database, - E: Executor<'c, Database = DB>, + E: Executor<'e, Database = DB>, { executor.fetch_many(self) } @@ -213,14 +201,11 @@ impl<'q> RawSql<'q> { /// To avoid exhausting available memory, ensure the result set has a known upper bound, /// e.g. using `LIMIT`. #[inline] - pub fn fetch_all<'e, 'c: 'e, E, DB>( - self, - executor: E, - ) -> BoxFuture<'e, crate::Result>> + pub fn fetch_all<'e, E, DB>(self, executor: E) -> BoxFuture<'e, crate::Result>> where 'q: 'e, DB: Database, - E: Executor<'c, Database = DB>, + E: Executor<'e, Database = DB>, { executor.fetch_all(self) } @@ -238,14 +223,11 @@ impl<'q> RawSql<'q> { /// /// Otherwise, you might want to add `LIMIT 1` to your query. #[inline] - pub fn fetch_one<'e, 'c: 'e, E, DB>( - self, - executor: E, - ) -> BoxFuture<'e, crate::Result> + pub fn fetch_one<'e, E, DB>(self, executor: E) -> BoxFuture<'e, crate::Result> where 'q: 'e, DB: Database, - E: Executor<'c, Database = DB>, + E: Executor<'e, Database = DB>, { executor.fetch_one(self) } @@ -263,14 +245,11 @@ impl<'q> RawSql<'q> { /// /// Otherwise, you might want to add `LIMIT 1` to your query. #[inline] - pub async fn fetch_optional<'e, 'c: 'e, E, DB>( - self, - executor: E, - ) -> crate::Result + pub async fn fetch_optional<'e, E, DB>(self, executor: E) -> crate::Result where 'q: 'e, DB: Database, - E: Executor<'c, Database = DB>, + E: Executor<'e, Database = DB>, { executor.fetch_one(self).await }