エラーで理解するPostgreSQL

## はじめに
この記事は[ディップ株式会社 Advent Calendar 2023の](https://qiita.com/advent-calendar/2023/dip-dev)の初日投稿です！


## この記事ついて
エラーってよくわからないですよね？
PostgreSQLってよくわからないですよね？

そんなわからないを理解できるようにまとめたのがこの記事。
エラーについてわかるようになります。
PostgreSQLについても理解が深まります。

## 記事を読むことで得られること
以下を知ることでPostgreSQLについて理解が深まります。
- PostgreSQLに関わるエラー
- PostgreSQL内の処理について


## エラーで理解するPostgreSQL
早速本題に入りましょう

### PostgreSQLの処理について
初めに理解を深めるのはPostgreSQLの処理について
PostgreSQLがあるサーバーへのリクエストを送った後、返ってくるまで（問い合わせ）の間の理解がないとエラーの原因を突き止めるのに苦労します。具体的にはSQLの構文エラーなのにネットワーク周りを調査したりなど。エラーを読んで理解しないと的外れな行動をとってしまうので、PostgreSQLのどこでどんなエラーが出たのかがわかるようにするために処理について理解を深めていきます。

ものすごく簡略な処理の流れを図にまとめました[^1]。
[^1]: 接続に関しては詳細を省いています。

![問い合わせ処理の流れ.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572072/31a2b3b7-40f4-a7fa-a144-ec854ccf5deb.png)

図の内容は以下の通り
① クライアントから接続を要求します。
② 問題なければ接続を確立します。
③ クライアントからSQLを発行します。
④ 内部処理を終えて結果をクライアントへ返します。

簡単に処理の流れを把握したところで次はエラーと合わせてPostgreSQLの理解を深めて行きましょう

### エラーとPostgreSQLの処理
ここからエラーについて共有していきます。
エラーがPostgreSQLの処理のどこでどのように起きているのかも合わせてまとめていきます。

#### FATAL: remaining connection slots are reserved for non-replication superuser connections
翻訳すると「残りの接続スロットはレプリケーションユーザではないスーパーユーザ用に予約されています」
以下のように①の接続を要求した際に出るエラーです。
エラーは以下のように出ます。

``` bash
-bash-4.2$ psql -U test
ユーザ test のパスワード:
psql: FATAL: remaining connection slots are reserved for non-replication superuser connections
```

接続に対して個別のプロセスを立ち上げますが、このプロセスの最大数を指定するのが
`max_connections`パラメータで指定できます。
`max_connections`パラメータで指定した値によって空きがありましたが、`superuser_reserved_connections`パラメータでスーパーユーザーの接続のために予約されているため非スーパーユーザーは接続ができなかったために出るエラーです。

![fatal_connections.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572072/84cf200f-d76a-500b-e474-da227eec96eb.png)


#### ERROR:  syntax error at or near "serect"
誤ったSQL文を実行すると起きます。例えば以下のようなエラー

``` sql
postgres=# serect * from table;
ERROR:  syntax error at or near "serect"
LINE 1: serect * from table;
      ^
```
構文解析過程でエラーとなる。
詳細にいうと初期解析（パース）の段階で構文が正しいかどうかをチェックしたタイミングでエラーとなる。

![error_syntax.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572072/e0e9da85-464b-ae14-bc72-67c2c0ba5232.png)

#### ERROR: relation "xxx" does not exist
存在しないテーブルなどを指定した際にでるエラー

``` sql
postgres=# select * from aaa;
ERROR:  relation "aaa" does not exist
LINE 1: select * from aaa;
                      ^
```

このエラーはプランナ／オプティマイザの段階で出るエラー
プランナ／オプティマイザでは問い合わせの中で使用される個々のリレーション（テーブル）をスキャンするための計画を生成することから始めます。その際にテーブルなどの存在確認をしているためなければエラーとなります。

![error_relation.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572072/90fe8e02-f594-da1b-ebc7-a470b6d56b39.png)

#### 実行時エラー (Runtime Errors)
対象のオブジェクトに対して権限を持っていないのに実行しようとした際に出るエラー

``` sql
postgres=# select * from aaa;
ERROR:  permission denied for table aaa
                      ^
```

このエラーはプランナ／オプティマイザの段階で出るエラー
実行計画が作成された後、クエリの実行前に権限チャックが行われます。
その際に必要な権限を持っていなければエラーとなります。

![error_relation.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572072/90fe8e02-f594-da1b-ebc7-a470b6d56b39.png)

## まとめ
今回まとめた内容にはまだまだ足りない部分があるようです。
例えばパーサーと書き換えプロセスの間にはアナライザーという段階があるようなのですが、信憑性の高い記事がうまく見つけられなかったので、今後も問い合わせの処理については理解を深めていきたいと思います。
それでも簡単に処理を理解することで対応できる範囲が広がると思うので是非ともこの記事をきっかけにより理解を深めてみてください。

## 参考
[内部構造から学ぶPostgreSQL―設計・運用計画の鉄則](https://amzn.to/3N16LzS)
[PostgreSQLインサイド概要](https://www.sraoss.co.jp/wp-content/uploads/files/event_seminar/material/2006/inside.pdf)
[Oracle技術者のための PostgreSQL自習書](https://pgecons-sec-tech.github.io/tech-report/pdf/wg2_PostgresSelfStudyBook.pdf)
[PostgreSQL入門 ∼クエリ処理編∼](https://edbjapan.com/webinar/PostgreSQ_Basics_Query_220216_webinar.pdf)
[PostgreSQL: Query Processing](https://dev.to/hassanrehan/postgresql-query-processing-39kb)