🤖
RustでPostgreSQLでプロシージャの戻りを取得する
目的
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