diff --git a/ci/builder/requirements.txt b/ci/builder/requirements.txt index c85a860cb0435..23f3d61501f6c 100644 --- a/ci/builder/requirements.txt +++ b/ci/builder/requirements.txt @@ -50,9 +50,8 @@ pdoc==16.0.0 pg8000==1.31.6 prettytable==3.18.0 psutil==7.2.2 -# TODO: Bump psycopg/psycopg-binary to >= 3.3.6 when SQL-840 is fixed -psycopg==3.3.3 -psycopg-binary==3.3.3 +psycopg==3.3.6 +psycopg-binary==3.3.6 pydantic==2.14.1 pyelftools==0.33 pyjwt==2.15.1 diff --git a/src/pgwire/src/protocol.rs b/src/pgwire/src/protocol.rs index 103267937ccdc..04e2f1965ae2a 100644 --- a/src/pgwire/src/protocol.rs +++ b/src/pgwire/src/protocol.rs @@ -1485,12 +1485,14 @@ where self.send_parameter_statuses(params).await?; } Ok(_) => {} - Err(err) => { + Err(err) if action == EndTransactionAction::Commit => { self.send(BackendMessage::ErrorResponse( err.into_response(Severity::Error), )) .await?; } + // Only one error can be reported, ignore. + Err(_) => {} } Ok(()) } diff --git a/test/cluster/mzcompose.py b/test/cluster/mzcompose.py index 3c7ba8f4038ef..498c903f842e8 100644 --- a/test/cluster/mzcompose.py +++ b/test/cluster/mzcompose.py @@ -3302,6 +3302,25 @@ def fetch_metrics() -> Metrics: assert 0 < time < 10, f"got {time}" +def workflow_test_dropped_role_begin(c: Composition) -> None: + c.up("materialized") + c.sql("CREATE ROLE dropped_role") + + with c.sql_connection(user="dropped_role") as conn: + conn.autocommit = False + c.sql("DROP ROLE dropped_role") + + # Psycopg first sends an implicit BEGIN. Duplicate error responses + # mask the dropped-role error with a client-side InternalError. + try: + conn.execute("SELECT 1") + except psycopg.errors.InsufficientPrivilege as e: + assert "was concurrently dropped" in str(e), str(e) + assert conn.info.transaction_status == psycopg.pq.TransactionStatus.IDLE + else: + raise AssertionError("query succeeded after its role was dropped") + + def workflow_test_pgwire_metrics(c: Composition) -> None: """Test metrics collected in the Adapter frontend, i.e., `pgwire.rs`"""