PostgreSQLをソースコードからビルドしてplpythonを使う手順

PL/Pythonは、PostgreSQLでストアドプロシージャあるいはストアドファンクションをPython言語で記述するための手続き言語です。
今回、PostgreSQLをソースコードからビルドしてPL/Pythonを使えるようにする手順をまとめました。
システムにpython2とpython3が両方インストールされていたので、PL/Pythonが任意のバージョンのpythonを使う方法についても説明します。

使用したPostgreSQLのバージョンは14.1です。その他、環境・バージョンは以下の通りです。

```sh
$ cat /etc/redhat-release 
CentOS Linux release 8.5.2111
$ which python
/usr/bin/python
$ ls -l /usr/bin/python
lrwxrwxrwx 1 root root 7 12月 21 11:00 /usr/bin/python -> python2
$ python2 --version
Python 2.7.18
$ python3 --version
Python 3.6.8
```

# 背景
PL/PythonでPython3を使おうと思ったら、plpython3u（Python3用のPL/PythonのEXTENSION）が存在しなくてエラーになりました。

```
postgres=# SELECT * FROM pg_available_extensions;
  name   | default_version | installed_version |           comment            
---------+-----------------+-------------------+------------------------------
 plpgsql | 1.0             | 1.0               | PL/pgSQL procedural language
(1 row)

postgres=# CREATE EXTENSION plpython3u;
2021-12-21 11:17:47.096 JST [178472] ERROR:  could not open extension control file "/usr/local/pgsql/share/extension/plpython3u.control": そのようなファイルやディレクトリはありません
2021-12-21 11:17:47.096 JST [178472] STATEMENT:  CREATE EXTENSION plpython3u;
ERROR:  could not open extension control file "/usr/local/pgsql/share/extension/plpython3u.control": そのようなファイルやディレクトリはありません
```

PostgreSQLをソースコードからビルドする際にオプションを付ける必要があるとわかりましたが（詳細は後述）、やってみてもplpython3uが見つかりませんでした。  

以下のように、plpython2u（Python2用のPL/PythonのEXTENSION）ならありました。

```
postgres=# SELECT * FROM pg_available_extensions;
    name    | default_version | installed_version |                  comment    
              
------------+-----------------+-------------------+-----------------------------
--------------
 plpgsql    | 1.0             | 1.0               | PL/pgSQL procedural language
 plpython2u | 1.0             |                   | PL/Python2U untrusted proced
ural language
 plpythonu  | 1.0             |                   | PL/PythonU untrusted procedu
ral language
(3 rows)

```

原因としては、PostgreSQLビルド時にpythonコマンドによって使うPythonのバージョンが決定するためでした。
本環境ではpythonコマンドはpython2にシンボリックリンクしていたので、バージョン2が使われていたようです。

# PostgreSQLのビルド
前置きが長くなりましたが、システムの設定を変更せずにPostgreSQLでPL/Pythonがpython3を使えるようにする手順を説明します。

まず、configure時に--with-pythonオプションを使用します。
さらに、今回はpython3を使いたいのでPYTHON=python3も指定します。

```sh
$ ./configure --with-python PYTHON=python3
make
sudo make install
```

* configureの出力を見ると、以下のようにpython3が使われていることがわかります。

    ```
    ...
    checking for PYTHON... python3
    configure: using python 3.6.8 (default, Sep 10 2021, 09:13:53) 
    ...
    ```

* もしpython2が使われている場合は以下のようになります。

    ```
    ...
    checking for python... /usr/bin/python
    configure: using python 2.7.18 (default, Aug 25 2021, 15:50:49) 
    ...
    ```

PostgreSQLインストール後は、PostgreSQLの起動からDBの作成までは通常通り行います。

```sh
$ initdb DBクラスタのパス
$ pg_ctl -D DBクラスタのパス start
```

# PL/Pythonのインストール
以下のように、plpython3uが利用可能になっているはずです。

```
postgres=# SELECT * FROM pg_available_extensions;
    name    | default_version | installed_version |                  comment    
              
------------+-----------------+-------------------+-----------------------------
--------------
 plpgsql    | 1.0             | 1.0               | PL/pgSQL procedural language
 plpython3u | 1.0             |                   | PL/Python3U untrusted proced
ural language
(2 rows)

```
あとは、plpython3uをインストールすればOKです。

```
$ psql postgres
postgres# CREATE EXTENSION plpython3u;
CREATE EXTENSION
```

# 確認
Pythonのバージョンを出力するストアドファンクションを作成して、結果を確かめてみます。

```
postgres=# CREATE FUNCTION python_version () RETURNS text AS $$
  import sys
  return sys.version
$$ LANGUAGE plpython3u;
CREATE FUNCTION
postgres=# SELECT python_version();
             python_version              
-----------------------------------------
 3.6.8 (default, Sep 10 2021, 09:13:53) +
 [GCC 8.5.0 20210514 (Red Hat 8.5.0-3)]
(1 row)

```
3.6.8と表示され、Python3が使われていることが確認できました。

# おわりに
PostgreSQLのPL/Pythonで使うPythonのバージョンを指定する方法を説明しました。
PostgreSQLが使用するPythonのバージョンは、configure時のpythonコマンドに依存し、PYTHON=で指定することができます。
もしそれを指定しなかった場合、まずpythonコマンド、それがnot foundならpython3コマンド、それもnot foundならpython2コマンド、という順番で探索しているようです。

# 参考文献
https://www.postgresql.jp/document/13/html/install-procedure.html