PostgreSQLで特定のファンクションをダンプする

最近、仕事ではドキュメントを書いてばかりです。
しっかりとドキュメント管理できていない状況で、過去に作ったファンクションの仕様書を作るという、古より伝わる悪いことをしています。
その中作業の中で、ファンクションの定義を出力しくなりました。
いや、ソース管理に登録されてるファンクションのソースが信用できないというか、最新かどうか確認もしたかったので・・・

pg_procテーブルだと、ファンクションの中身しか確認できません。
ググると、pg_dumpでダンプしたファイルから取り出せる例がありましたが、ちょっとわかりづらかったのでまとめておこうかと思います。

# やることの概要

やることは以下の2点。

1. pg_dumpでカスタム形式でスキーマのみをダンプする
2. pg_restoreでダンプしたいファンクションを指定して実行

# 実践　引数のないファンクションのダンプ

以下のようなファンクションを登録します。

```sql
CREATE FUNCTION testproc() RETURNS text
AS $$
BEGIN
	RETURN 'Hello World';

END; $$
LANGUAGE plpgsql;
```

スキーマをダンプします。

```bash
$ pg_dump -Fc -s -f test.fc testdb
$ ls
test.fc
```

次にファンクションをリストアします。

```bash
$ pg_restore -P "testproc()" -f testproc.sql test.fc
$ cat testproc.sql
--
-- PostgreSQL database dump
--

-- Dumped from database version 12.2 (Ubuntu 12.2-4)
-- Dumped by pg_dump version 12.2 (Ubuntu 12.2-4)

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

--
-- Name: testproc(); Type: FUNCTION; Schema: public; Owner: krohigewagma
--

CREATE FUNCTION public.testproc() RETURNS text
    LANGUAGE plpgsql
    AS $$
BEGIN
 RETURN 'Hello World';

END; $$;


ALTER FUNCTION public.testproc() OWNER TO krohigewagma;

--
-- PostgreSQL database dump complete
--
```

このような感じでファンクションの定義を取り出しました。

# 実践 引数があるファンクションのダンプ

次は以下のようなファンクションを登録して、ダンプします。

```sql
CREATE FUNCTION testproc2(name varchar, message varchar) RETURNS text
AS $$
BEGIN
	RETURN 'Hello World ' || name || '!' || message;

END; $$
LANGUAGE plpgsql;
```

先ほどと同じく、スキーマをダンプします。

```bash
$ pg_dump -Fc -s -f test.fc testdb
```

次にファンクションをリストアします。

```bash
$ pg_restore -P "testproc2(character varying, character varying)" -f testproc2.sql test.fc
$ cat testproc2.sql
--
-- PostgreSQL database dump
--

-- Dumped from database version 12.2 (Ubuntu 12.2-4)
-- Dumped by pg_dump version 12.2 (Ubuntu 12.2-4)

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

--
-- Name: testproc2(character varying, character varying); Type: FUNCTION; Schema: public; Owner: krohigewagma
--

CREATE FUNCTION public.testproc2(name character varying, message character varying) RETURNS text
    LANGUAGE plpgsql
    AS $$
BEGIN
 RETURN 'Hello World ' || name || '!' || message;

END; $$;


ALTER FUNCTION public.testproc2(name character varying, message character varying) OWNER TO krohigewagma;

--
-- PostgreSQL database dump complete
--
```

## 注意点１.引数の型名の指定
型を記載する場合、varcharはcharacter varyingというように省略前の名称で記載する必要があります。
ほかにもあると思いますが、調べきれていません。
ちなみに、カスタム形式じゃなくて普通にテキストでスキーマをダンプして、そこに書いてある型名で書けば間違いありません。
(なんか本末転倒な・・・)

## 注意点２.引数の区切りは", "(カンマスペース)で区切る

```
testproc2(character varying, character varying)
```

はOKなんですが

```
testproc2(character varying,character varying)
```

は失敗します。
スペースくらい融通利かせて欲しいところです。

# 一工夫する場合
pg_procテーブルと、pg_typeテーブルを使うことで、DBのファンクションをファンクション別のファイルで出力することも可能です。
ちょっと考えてみるのもよいかと思います。

# 最後に
たぶん、業務で出力したくなるケースってそんなに多くはないと思います。
しかし、知っておいて損はないと思います。

# 参考

- [PostgreSQLのpg_dumpで単一のfunctionのみ取得する](https://jikkenjo.net/1966.html)