Skip to content
12 changes: 11 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ required-features = ["sqlite"]
[[test]]
name = "sqlite-any"
path = "tests/sqlite/any.rs"
required-features = ["sqlite"]
required-features = ["sqlite", "any"]

[[test]]
name = "sqlite-types"
Expand Down Expand Up @@ -401,6 +401,11 @@ name = "mysql-rustsec"
path = "tests/mysql/rustsec.rs"
required-features = ["mysql"]

[[test]]
name = "mysql-any"
path = "tests/mysql/any.rs"
required-features = ["mysql", "any"]

#
# PostgreSQL
#
Expand Down Expand Up @@ -454,3 +459,8 @@ required-features = ["postgres"]
name = "postgres-rustsec"
path = "tests/postgres/rustsec.rs"
required-features = ["postgres", "macros", "migrate"]

[[test]]
name = "postgres-any"
path = "tests/postgres/any.rs"
required-features = ["postgres", "any"]
15 changes: 8 additions & 7 deletions sqlx-mysql/src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl AnyConnectionBackend for MySqlConnection {
.try_flatten_stream()
.map(|res| {
Ok(match res? {
Either::Left(result) => Either::Left(map_result(result)),
Either::Left(result) => Either::Left(result.into()),
Either::Right(row) => Either::Right(AnyRow::try_from(&row)?),
})
}),
Expand Down Expand Up @@ -210,11 +210,12 @@ impl<'a> TryFrom<&'a AnyConnectOptions> for MySqlConnectOptions {
}
}

fn map_result(result: MySqlQueryResult) -> AnyQueryResult {
AnyQueryResult {
rows_affected: result.rows_affected,
// Don't expect this to be a problem
#[allow(clippy::cast_possible_wrap)]
last_insert_id: Some(result.last_insert_id as i64),
/// This conversion attempts to save last_insert_id by converting to i64.
impl From<MySqlQueryResult> for AnyQueryResult {
fn from(done: MySqlQueryResult) -> Self {
AnyQueryResult {
rows_affected: done.rows_affected(),
last_insert_id: done.last_insert_id().try_into().ok(),
}
}
}
10 changes: 0 additions & 10 deletions sqlx-mysql/src/query_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,3 @@ impl Extend<MySqlQueryResult> for MySqlQueryResult {
}
}
}
#[cfg(feature = "any")]
/// This conversion attempts to save last_insert_id by converting to i64.
impl From<MySqlQueryResult> for sqlx_core::any::AnyQueryResult {
fn from(done: MySqlQueryResult) -> Self {
sqlx_core::any::AnyQueryResult {
rows_affected: done.rows_affected(),
last_insert_id: done.last_insert_id().try_into().ok(),
}
}
}
12 changes: 7 additions & 5 deletions sqlx-postgres/src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl AnyConnectionBackend for PgConnection {
.try_flatten_stream()
.map(
move |res: sqlx_core::Result<Either<PgQueryResult, PgRow>>| match res? {
Either::Left(result) => Ok(Either::Left(map_result(result))),
Either::Left(result) => Ok(Either::Left(result.into())),
Either::Right(row) => Ok(Either::Right(AnyRow::try_from(&row)?)),
},
),
Expand Down Expand Up @@ -243,9 +243,11 @@ impl<'a> TryFrom<&'a AnyConnectOptions> for PgConnectOptions {
}
}

fn map_result(res: PgQueryResult) -> AnyQueryResult {
AnyQueryResult {
rows_affected: res.rows_affected(),
last_insert_id: None,
impl From<PgQueryResult> for AnyQueryResult {
fn from(done: PgQueryResult) -> Self {
AnyQueryResult {
rows_affected: done.rows_affected(),
last_insert_id: None,
}
}
}
10 changes: 0 additions & 10 deletions sqlx-postgres/src/query_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,3 @@ impl Extend<PgQueryResult> for PgQueryResult {
}
}
}

#[cfg(feature = "any")]
impl From<PgQueryResult> for sqlx_core::any::AnyQueryResult {
fn from(done: PgQueryResult) -> Self {
sqlx_core::any::AnyQueryResult {
rows_affected: done.rows_affected,
last_insert_id: None,
}
}
}
17 changes: 12 additions & 5 deletions sqlx-sqlite/src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl AnyConnectionBackend for SqliteConnection {
.try_flatten_stream()
.map(
move |res: sqlx_core::Result<Either<SqliteQueryResult, SqliteRow>>| match res? {
Either::Left(result) => Ok(Either::Left(map_result(result))),
Either::Left(result) => Ok(Either::Left(result.into())),
Either::Right(row) => Ok(Either::Right(AnyRow::try_from(&row)?)),
},
),
Expand Down Expand Up @@ -231,9 +231,16 @@ fn map_arguments(args: AnyArguments) -> SqliteArguments {
}
}

fn map_result(res: SqliteQueryResult) -> AnyQueryResult {
AnyQueryResult {
rows_affected: res.rows_affected(),
last_insert_id: None,
impl From<SqliteQueryResult> for AnyQueryResult {
fn from(done: SqliteQueryResult) -> Self {
// logic as per: https://www.sqlite.org/c3ref/last_insert_rowid.html
let last_insert_id = match done.last_insert_rowid() {
0 => None,
n => Some(n),
};
AnyQueryResult {
rows_affected: done.rows_affected(),
last_insert_id,
}
}
}
14 changes: 0 additions & 14 deletions sqlx-sqlite/src/query_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,3 @@ impl Extend<SqliteQueryResult> for SqliteQueryResult {
}
}
}

#[cfg(feature = "any")]
impl From<SqliteQueryResult> for sqlx_core::any::AnyQueryResult {
fn from(done: SqliteQueryResult) -> Self {
let last_insert_id = match done.last_insert_rowid() {
0 => None,
n => Some(n),
};
sqlx_core::any::AnyQueryResult {
rows_affected: done.rows_affected(),
last_insert_id,
}
}
}
26 changes: 26 additions & 0 deletions tests/mysql/any.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use sqlx::Any;
use sqlx_test::new;

/// ensure Any type with MySQL backing returns last_insert_id properly
/// https://github.com/launchbadge/sqlx/issues/2982
#[sqlx_macros::test]
async fn any_sets_last_insert_id() -> anyhow::Result<()> {
sqlx::any::install_default_drivers();

let mut conn = new::<Any>().await?;
// syntax as per: https://dev.mysql.com/doc/refman/9.6/en/example-auto-increment.html
let _ = sqlx::query(
"CREATE TEMPORARY TABLE users (id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, name TEXT NOT NULL)",
)
.execute(&mut conn)
.await?;

let result = sqlx::query("INSERT INTO users (name) VALUES (?)")
.bind("Glorbo")
.execute(&mut conn)
.await?;

assert_eq!(result.last_insert_id(), Some(1));

Ok(())
}
27 changes: 27 additions & 0 deletions tests/postgres/any.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use sqlx::Any;
use sqlx_test::new;

/// ensure Any type with PostgreSQL backing returns last_insert_id properly
/// https://github.com/launchbadge/sqlx/issues/2982
#[sqlx_macros::test]
async fn any_sets_last_insert_id() -> anyhow::Result<()> {
sqlx::any::install_default_drivers();

let mut conn = new::<Any>().await?;
// syntax as per: https://www.postgresql.org/docs/current/ddl-identity-columns.html
let _ = sqlx::query(
"CREATE TEMPORARY TABLE users (id INTEGER GENERATED ALWAYS AS IDENTITY, name TEXT NOT NULL)",
)
.execute(&mut conn)
.await?;

let result = sqlx::query("INSERT INTO users (name) VALUES ($1)")
.bind("Glorbo")
.execute(&mut conn)
.await?;

// NOTE: PgQueryResult does not implement an equivalent concept and can only return None
assert_eq!(result.last_insert_id(), None);

Ok(())
}
24 changes: 24 additions & 0 deletions tests/sqlite/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,27 @@ async fn issue_3179() -> anyhow::Result<()> {

Ok(())
}

/// ensure Any type with SQLite backing returns last_insert_id properly
/// https://github.com/launchbadge/sqlx/issues/2982
#[sqlx_macros::test]
async fn any_sets_last_insert_id() -> anyhow::Result<()> {
sqlx::any::install_default_drivers();

let mut conn = new::<Any>().await?;
// syntax as per: https://sqlite.org/autoinc.html
let _ = sqlx::query(
"CREATE TEMPORARY TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)",
)
.execute(&mut conn)
.await?;

let result = sqlx::query("INSERT INTO users (name) VALUES (?)")
.bind("Glorbo")
.execute(&mut conn)
.await?;

assert_eq!(result.last_insert_id(), Some(1));

Ok(())
}
Loading