Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handling of deferred constraints #2913

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions sqlx-postgres/src/connection/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,13 +402,18 @@ impl<'c> Executor<'c> for &'c mut PgConnection {
let s = self.run(sql, arguments, 1, persistent, metadata).await?;
pin_mut!(s);

while let Some(s) = s.try_next().await? {
if let Either::Right(r) = s {
return Ok(Some(r));
// With deferred constraints we need to check all responses as we
// could get a OK response (with uncommitted data), only to get an
// error response after (when the deferred constraint is actually
// checked).
let mut ret = None;
while let Some(result) = s.try_next().await? {
match result {
Either::Right(r) if ret.is_none() => ret = Some(r),
_ => {}
}
}

Ok(None)
Ok(ret)
})
}

Expand Down
24 changes: 24 additions & 0 deletions tests/postgres/postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1813,3 +1813,27 @@ async fn test_shrink_buffers() -> anyhow::Result<()> {

Ok(())
}

#[sqlx_macros::test]
async fn test_error_handling_with_deferred_constraints() -> anyhow::Result<()> {
let mut conn = new::<Postgres>().await?;

sqlx::query("CREATE TABLE IF NOT EXISTS deferred_constraint ( id INTEGER PRIMARY KEY )")
.execute(&mut conn)
.await?;

sqlx::query("CREATE TABLE IF NOT EXISTS deferred_constraint_fk ( fk INTEGER CONSTRAINT deferred_fk REFERENCES deferred_constraint(id) DEFERRABLE INITIALLY DEFERRED )")
.execute(&mut conn)
.await?;

let result: sqlx::Result<i32> =
sqlx::query_scalar("INSERT INTO deferred_constraint_fk VALUES (1) RETURNING fk")
.fetch_one(&mut conn)
.await;

let err = result.unwrap_err();
let db_err = err.as_database_error().unwrap();
assert_eq!(db_err.constraint(), Some("deferred_fk"));

Ok(())
}
Loading