PostgreSQLの拡張機能がどの言語によって実装されているか調べる。

# はじめに
にゃーん。趣味でポスグレをやっている者だ。

とある事情で、表題にあるように、PostgreSQLの拡張機能(EXTENSION)に含まれる関数が、どの言語で実装されているかを調べることになった。

# SQL例
以下のようなSQLを実行することで、指定したEXTENSIONに含まれるSQL関数が、どの言語(C, SQL, PL/pgSQL)で実装されているかを調べられる。

```sql
--
-- EXTENSIONに含まれる関数が何の言語で実装されているか表示する
-- (PostgreSQL 9.1以降)
--
SELECT t.objid, p.proname, l.lanname FROM
(
  SELECT objid, pg_identify_object_as_address(classid, objid, 0) r
  FROM pg_catalog.pg_depend
  WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND
    refobjid = (SELECT oid FROM pg_extension WHERE extname = 'pg_fraction') AND
    deptype = 'e'
  ORDER BY 1
) t JOIN pg_proc p ON (t.objid = p.oid)
    JOIN pg_language l ON (p.prolang = l.oid)
WHERE (r).type = 'function';
```
上記の例だと、[pg_fraction](https://github.com/nuko-yokohama/pg_fraction)という拡張（これは自分が学習用につくった分数型EXTENSION）に含まれるSQL関数名とそれを実装した言語を表示する。
実行例はこんな感じ。

```sql
--
-- EXTENSIONに含まれる関数が何の言語で実装されているか表示する
-- (PostgreSQL 9.1以降)
--
SELECT t.objid, p.proname, l.lanname FROM
(
  SELECT objid, pg_identify_object_as_address(classid, objid, 0) r
  FROM pg_catalog.pg_depend
  WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND
    refobjid = (SELECT oid FROM pg_extension WHERE extname = 'pg_fraction') AND
    deptype = 'e'
  ORDER BY 1
) t JOIN pg_proc p ON (t.objid = p.oid)
    JOIN pg_language l ON (p.prolang = l.oid)
WHERE (r).type = 'function';
 objid |      proname       | lanname
-------+--------------------+---------
 16401 | fraction_in        | c
 16402 | fraction_out       | c
 16404 | get_value          | c
 16405 | fraction_add       | c
 16407 | fraction_sub       | c
 16409 | fraction_mul       | c
 16411 | fraction_div       | c
 16413 | fraction_max       | c
 16415 | fraction_min       | c
 16417 | fraction_to_float8 | c
 16419 | int32_to_fraction  | c
 16421 | fraction_eq        | c
 16423 | fraction_ne        | c
 16425 | fraction_lt        | c
 16427 | fraction_gt        | c
 16429 | fraction_le        | c
 16431 | fraction_ge        | c
 16433 | fraction_cmp       | c
(18 rows)
```

もう一つの例として、SQLのみで作成されたEXTENSIONの例を示す。このEXTENSIONは、PostgreSQL文書の[拡張の例](https://www.postgresql.jp/document/11/html/extend-extensions.html#EXTEND-EXTENSIONS-EXAMPLE)に記載されていた、pairというデータ型拡張である。データ型を実装するためには、結局のところSQL関数を実装する必要がある。
で、このSQL関数はSQLで作成されているので、実行するとこんな感じになる。

```sql
testdb=# SELECT t.objid, p.proname, l.lanname FROM
(
  SELECT objid, pg_identify_object_as_address(classid, objid, 0) r
  FROM pg_catalog.pg_depend
  WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND
    refobjid = (SELECT oid FROM pg_extension WHERE extname = 'pair') AND
    deptype = 'e'
  ORDER BY 1
) t JOIN pg_proc p ON (t.objid = p.oid)
    JOIN pg_language l ON (p.prolang = l.oid)
WHERE (r).type = 'function';
 objid |   proname   | lanname
-------+-------------+---------
 16389 | pair        | sql
 16391 | lower       | sql
 16392 | pair_concat | sql
(3 rows)

testdb=#
```

本当はこれをPREPARED STATEMENTで組んでEXECUTEすべきなんだろうけど、まあ、やり方は分かっているので、ここではあえて書かない。

# おわりに
最初はpsqlの`\dx+`メタコマンドとかで簡単にだせるかなー？と思っていたのだが、実際にやってみると、そう単純なものじゃなかった。
でも、この調査の中で、[オブジェクト情報とアドレスの関数](https://www.postgresql.jp/document/9.6/html/functions-info.html#functions-info-object-table)という関数群がPostgreSQLに実装されていることもわかったので、なかなか為になる調べ物になりました。