PostgreSQL を CLion でデバッグしながら開発する

## TR;DL

CLion で PostgreSQL の開発はやるもんじゃない，素直に Vim (or Emacs) と GDB を使おう．

## 前提

- macOS Mojave 10.14
    - Homebrew で依存パッケージをインストール済み
- PostgreSQL 12
- CLion 2018.3

## ビルド & インストール

今回は `$HOME/.local` 配下にインストールする [^1]．
また，データベースの実体 (データベースクラスタ) は `$HOME/.local/pgsql/data` を指定することとする [^2]．

```shell
git clone git://git.postgresql.org/git/postgresql.git
cd postgresql
./configure --prefix=$HOME/.local --enable-debug --enable-cassert --enable-depend CFLAGS=-O0
make -j
make install
```

`./configure` のオプションについては [ここ](https://www.postgresql.org/docs/current/install-procedure.html) を参照．
以下，抜粋．

> When developing code inside the server, it is recommended to use the configure options `--enable-cassert` (which turns on many run-time error checks) and `--enable-debug` (which improves the usefulness of debugging tools).
> 
> If using GCC, it is best to build with an optimization level of at least `-O1`, because using no optimization (`-O0`) disables some important compiler warnings (such as the use of uninitialized variables). However, non-zero optimization levels can complicate debugging because stepping through compiled code will usually not match up one-to-one with source code lines. If you get confused while trying to debug optimized code, recompile the specific files of interest with `-O0`. An easy way to do this is by passing an option to make: make `PROFILE=-O0 file.o`.

PostgreSQL の開発にあたっては，アサーションチェックを有効にする `--enable-cassert` とコンパイル時にデバッグシンボルを含める `--enable-debug` を指定して `./configure` する．
GCC を使ってコンパイルする際は最適化レベルを `-O0` で指定してやると，デバッグしやすい最適化レベルになる．
また，ヘッダを変更した後の `make` で，関連するすべてのコードをコンパイルし直すオプション [^3] として `--enable-depend` も加えておく．

パスとデータベースクラスタの場所を環境変数に設定しておくと便利．

```shell
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH="$HOME/pgbuild/lib"' >> ~/.bashrc
echo 'export PGDATA="$HOME/.local/pgsql/data"' >> ~/.bashrc
source ~/.bashrc
```

次に，テスト用のデータベースの作成を行う．

```shell-session
% initdb 
The files belonging to this database system will be owned by user "sira".
This user must also own the server process.

The database cluster will be initialized with locales
  COLLATE:  C
  CTYPE:    UTF-8
  MESSAGES: C
  MONETARY: C
  NUMERIC:  C
  TIME:     C
The default database encoding has accordingly been set to "UTF8".
initdb: could not find suitable text search configuration for locale "UTF-8"
The default text search configuration will be set to "simple".

(snipped)

Success. You can now start the database server using:

    pg_ctl -D /Users/sira/.local/pgsql/data -l logfile start
```

データベースサーバーを動作させる．

```shell-session
% postgres
2019-05-23 22:54:22.721 JST [65596] LOG:  starting PostgreSQL 12beta1 on x86_64-apple-darwin18.0.0, compiled by Apple LLVM version 10.0.0 (clang-1000.10.44.4), 64-bit
2019-05-23 22:54:22.723 JST [65596] LOG:  listening on IPv6 address "::1", port 5432
2019-05-23 22:54:22.723 JST [65596] LOG:  listening on IPv4 address "127.0.0.1", port 5432
2019-05-23 22:54:22.724 JST [65596] LOG:  listening on Unix socket "/tmp/.s.PGSQL.5432"
2019-05-23 22:54:22.745 JST [65597] LOG:  database system was interrupted; last known up at 2019-05-23 22:45:17 JST
2019-05-23 22:54:22.828 JST [65597] LOG:  database system was not properly shut down; automatic recovery in progress
2019-05-23 22:54:22.831 JST [65597] LOG:  redo starts at 0/15E9CF0
2019-05-23 22:54:22.831 JST [65597] LOG:  invalid record length at 0/15E9DD8: wanted 24, got 0
2019-05-23 22:54:22.831 JST [65597] LOG:  redo done at 0/15E9DA0
2019-05-23 22:54:22.837 JST [65596] LOG:  database system is ready to accept connections
```

ここでは，`pg_ctl` ではなく，`postgres` コマンドを使っている．
デバッグの際に，`postgres -d 5` 等を指定することで詳細なログを確認できるためである．

動作しているプロセスを確認してみる．

```shell-session
% ps aux | grep postgres
sira             65481   0.0  0.0  4277252    844 s000  S+   10:50PM   0:00.00 grep --color=auto --color=auto postgres
sira             63694   0.0  0.0  4453812   1664   ??  Ss   10:40PM   0:00.00 postgres: logical replication launcher     
sira             63693   0.0  0.0  4317332    800   ??  Ss   10:40PM   0:00.01 postgres: stats collector     
sira             63692   0.0  0.0  4479412   2004   ??  Ss   10:40PM   0:00.01 postgres: autovacuum launcher     
sira             63691   0.0  0.0  4445488   5060   ??  Ss   10:40PM   0:00.02 postgres: walwriter     
sira             63690   0.0  0.0  4453680   2132   ??  Ss   10:40PM   0:00.04 postgres: background writer     
sira             63689   0.0  0.0  4445488   2368   ??  Ss   10:40PM   0:00.01 postgres: checkpointer     
sira             63687   0.0  0.1  4445764  14892   ??  Ss   10:40PM   0:00.03 /Users/sira/.local/bin/postgres -D /Users/sira/.local/pgsql/data
```

- `logical replication launcher`
- `stats collector`
- `walwriter`
- `background writer`
- `checkpointer`

などが走っている．

次に，新しいターミナルを開いて，データベースサーバーにクライアントプログラムから接続してみる．
まずは，データベースクラスタを `test` という名前で作成する．

```shell
createdb test
```

次に，作成したデータベース `test` にアクセスする．

```shell-session
% psql test
psql (12beta1)
Type "help" for help.

test=# 
```

上記のフロントエンドで SQL を実行することができる．

最後に，データベースサーバーをシャットダウンする方法を説明しておく．
サーバーを開いているターミナルで <kbd><kbd>Ctrl</kbd> + <kbd>C</kbd></kbd> してもいいが，

```
pg_ctl stop
```

でサーバープロセスにシグナルを送信してもよい．

## CLion の設定

PostgreSQL のソースコードが格納されているディレクトリを CLion で開き，プロジェクトルートに下記の `CMakeLists.txt` を作成する [^4]．

```
cmake_minimum_required(VERSION 3.13)
project(postgres)
add_custom_target(
        postgres
        COMMAND make -C ${PROJECT_SOURCE_DIR})
```

Debug Configurations を開き，以下のように設定する．

<img width="1183" alt="Screen Shot 2019-05-23 at 23.26.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95900/666bf0f7-d149-805c-bbed-6623ef397284.png">

Executable には，`postgresql/src/backend/postgres` にあるバイナリを指定する．
Program arguments のデータベースクラスタの指定は絶対パスで記述する必要がある．

## デバッグ

基本的には，データベースサーバーのプログラムをデバッグすることになる．

例えば，エントリポイントである `main` 関数の適当な行にブレークポイントを設定してデバッグボタンを押下すると，デバッガに変数の内容が表示される。

<img width="1552" alt="Screen Shot 2019-05-23 at 23.32.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95900/fd9a704e-710c-7108-ef7b-a3c2e2065bc2.png">

## 終わりに

`CMakeLists.txt` は `make` を走らせているだけなので，CLion でソースコードの補完機能が使えない．
PostgreSQL の `Makefile` をすべて `CMakeLists.txt` にリプレースするか，CLion に `ctags` を読み込んでもらう必要があるが，PostgreSQL 初心者で JetBrains の社員でもない私にはチョットキビシイ．．．

なんだかんだで，Vim (or Emacs) + GDB が最適解な気がする．
`src/tools/make_ctags` もあるし．

PostgreSQL の開発を行う際に参考になるのが，日本語の文献だと [篠田の虎の巻シリーズ](https://h50146.www5.hpe.com/services/ci/opensource/#report)，英語の文献だと [The Internals of PostgreSQL](http://www.interdb.jp/pg/) によくまとまっている．
あとは，PostgreSQL の [開発者メーリングリスト](https://www.postgresql.org/list/pgsql-hackers/) に登録しておくと，ハッカーたちの議論に参加することができる．

[^1]: XDG Base Directory Specification. https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
[^2]: PostgreSQL: Documentation: 11: 18.2. Creating a Database Cluster. https://www.postgresql.org/docs/current/creating-cluster.html
[^3]: Developer FAQ - PostgreSQL wiki. https://wiki.postgresql.org/wiki/Developer_FAQ#What_development_environment_is_required_to_develop_code.3F
[^4]: clion调试postgresql - -六月飞雪- - 博客园. https://www.cnblogs.com/lanhj/p/6354195.html