diff --git a/sqlx-postgres/src/connection/describe.rs b/sqlx-postgres/src/connection/describe.rs index 1adbd18dfe..e2ec5cc255 100644 --- a/sqlx-postgres/src/connection/describe.rs +++ b/sqlx-postgres/src/connection/describe.rs @@ -449,9 +449,15 @@ WHERE rngtypid = $1 let mut nullables = Vec::new(); - if let Some(outputs) = &explain.plan.output { + if let Explain::Plan( + plan @ Plan { + output: Some(outputs), + .. + }, + ) = &explain + { nullables.resize(outputs.len(), None); - visit_plan(&explain.plan, outputs, &mut nullables); + visit_plan(&plan, outputs, &mut nullables); } Ok(nullables) @@ -484,9 +490,13 @@ fn visit_plan(plan: &Plan, outputs: &[String], nullables: &mut Vec> } #[derive(serde::Deserialize)] -struct Explain { - #[serde(rename = "Plan")] - plan: Plan, +enum Explain { + /// {"Plan": ...} -- returned for most statements + Plan(Plan), + /// The string "Utility Statement" -- returned for + /// a CALL statement + #[serde(rename = "Utility Statement")] + UtilityStatement, } #[derive(serde::Deserialize)] diff --git a/tests/postgres/macros.rs b/tests/postgres/macros.rs index 7933ebf6a9..be2271e9a5 100644 --- a/tests/postgres/macros.rs +++ b/tests/postgres/macros.rs @@ -96,6 +96,19 @@ async fn test_void() -> anyhow::Result<()> { Ok(()) } +#[sqlx_macros::test] +async fn test_call_procedure() -> anyhow::Result<()> { + let mut conn = new::().await?; + + let row = sqlx::query!(r#"CALL forty_two(null)"#) + .fetch_one(&mut conn) + .await?; + + assert_eq!(row.forty_two, Some(42)); + + Ok(()) +} + #[sqlx_macros::test] async fn test_query_file() -> anyhow::Result<()> { let mut conn = new::().await?; diff --git a/tests/postgres/setup.sql b/tests/postgres/setup.sql index 56edaf99fd..039e08d86f 100644 --- a/tests/postgres/setup.sql +++ b/tests/postgres/setup.sql @@ -41,3 +41,6 @@ CREATE TABLE products ( name TEXT, price NUMERIC CHECK (price > 0) ); + +CREATE OR REPLACE PROCEDURE forty_two(INOUT forty_two INT = NULL) + LANGUAGE plpgsql AS 'begin forty_two := 42; end;';