🤖

RustでPostgreSQLでプロシージャの戻りを取得する

2024/03/02に公開

目的

PostgreSQLのプロシージャでは、引数にOUTを指定することで、Rust側で値を取得することができます。今回はこれをやってみます。
リポジトリはこちら。

コード

ここではp_resultをINOUTとして宣言しています。入力と戻り値をここで管理します。

PostgreSQL

2つの引数を受け取って、プロシージャの中で修正しています。

pg_get_procedure.sql
DROP TYPE IF EXISTS type_pg_get_procedure CASCADE;
CREATE TYPE type_pg_get_procedure AS (
  content TEXT
  ,count BIGINT
);

CREATE OR REPLACE PROCEDURE pg_get_procedure(
  p_result1 INOUT type_pg_get_procedure DEFAULT NULL
  ,p_result2 INOUT type_pg_get_procedure DEFAULT NULL
) AS $PROCEDURE$
DECLARE
BEGIN
  p_result1.content := 'xxx' || p_result1.content || 'xxx';
  p_result1.count := p_result1.count + 1;
  p_result2.content := 'yyy' || p_result2.content || 'yyy';
  p_result2.count := p_result2.count * 10;
END;
$PROCEDURE$ LANGUAGE plpgsql;

Rust

Rust側では1行返ってきます。引数の宣言順にカラムとして取得できます。

prodecude.rs
use deadpool_postgres::GenericClient;
use postgres_types::{FromSql, ToSql};

use crate::pool::PgClient;

const SQL: &str = r#"
CALL pg_get_procedure(p_result1 := $1, p_result2 := $2)
"#;

#[derive(Debug, ToSql, FromSql, PartialEq)]
#[postgres(name = "type_pg_get_procedure", rename_all = "snake_case")]
struct TypePgGetProcedure {
    content: String,
    count: i64,
}

pub(crate) async fn execute(pg_client: &PgClient) -> anyhow::Result<()> {
    let data1 = TypePgGetProcedure {
        content: "abc".to_string(),
        count: 1,
    };

    let data2 = TypePgGetProcedure {
        content: "efg".to_string(),
        count: 2,
    };

    let res = pg_client.query_one(SQL, &[&data1, &data2]).await?;
    let res1: TypePgGetProcedure = res.get(0);
    let res2: TypePgGetProcedure = res.get(1);
    assert_eq!("xxxabcxxx", res1.content);
    assert_eq!(2, res1.count);
    assert_eq!("yyyefgyyy", res2.content);
    assert_eq!(20, res2.count);

    Ok(())
}

まとめ

ストアードプロシージャーでデータのやり取りのコードも見てみました。ストアードファンクションもありますが、こちらは普通のテーブルをSELECTするのと変わらないので迷うことは無いと思います。今までのコードでも何度か出てるのでそちらを参考にしてください。

Discussion