Skip to content

Commit 31e541a

Browse files
Fix handling of deferred constraints for PostgreSQL (#2913)
1 parent 9d2c521 commit 31e541a

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

sqlx-postgres/src/connection/executor.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -402,13 +402,18 @@ impl<'c> Executor<'c> for &'c mut PgConnection {
402402
let s = self.run(sql, arguments, 1, persistent, metadata).await?;
403403
pin_mut!(s);
404404

405-
while let Some(s) = s.try_next().await? {
406-
if let Either::Right(r) = s {
407-
return Ok(Some(r));
405+
// With deferred constraints we need to check all responses as we
406+
// could get a OK response (with uncommitted data), only to get an
407+
// error response after (when the deferred constraint is actually
408+
// checked).
409+
let mut ret = None;
410+
while let Some(result) = s.try_next().await? {
411+
match result {
412+
Either::Right(r) if ret.is_none() => ret = Some(r),
413+
_ => {}
408414
}
409415
}
410-
411-
Ok(None)
416+
Ok(ret)
412417
})
413418
}
414419

tests/postgres/postgres.rs

+24
Original file line numberDiff line numberDiff line change
@@ -1813,3 +1813,27 @@ async fn test_shrink_buffers() -> anyhow::Result<()> {
18131813

18141814
Ok(())
18151815
}
1816+
1817+
#[sqlx_macros::test]
1818+
async fn test_error_handling_with_deferred_constraints() -> anyhow::Result<()> {
1819+
let mut conn = new::<Postgres>().await?;
1820+
1821+
sqlx::query("CREATE TABLE IF NOT EXISTS deferred_constraint ( id INTEGER PRIMARY KEY )")
1822+
.execute(&mut conn)
1823+
.await?;
1824+
1825+
sqlx::query("CREATE TABLE IF NOT EXISTS deferred_constraint_fk ( fk INTEGER CONSTRAINT deferred_fk REFERENCES deferred_constraint(id) DEFERRABLE INITIALLY DEFERRED )")
1826+
.execute(&mut conn)
1827+
.await?;
1828+
1829+
let result: sqlx::Result<i32> =
1830+
sqlx::query_scalar("INSERT INTO deferred_constraint_fk VALUES (1) RETURNING fk")
1831+
.fetch_one(&mut conn)
1832+
.await;
1833+
1834+
let err = result.unwrap_err();
1835+
let db_err = err.as_database_error().unwrap();
1836+
assert_eq!(db_err.constraint(), Some("deferred_fk"));
1837+
1838+
Ok(())
1839+
}

0 commit comments

Comments
 (0)