PG16：Fix tab completion for GRANT/REVOKE

# はじめに

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

この記事は[PostgreSQL 16 全部ぬこ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/pg16-all-nuko) 4日目の記事です。

今回は権限を制御する``GRANT``/``REVOKE``コマンドの``psql``TAB補完の改善について書きます。

# 概要

|項目|内容|
|:--|:--|
|タイトル|[Fix tab completion for GRANT/REVOKE](https://commitfest.postgresql.org/40/3942/)|
|Topic|Clients|
|ステータス|commited|
|Last modified|2022-11-18|
|概要|GRANT/REVOKEコマンドのTAB補完改善|

# 変更内容
## GRANT/REVOKEコマンド
``GRANT``/``REVOKE``コマンドは大きく分けて2つの機能を持っています。
* PostgreSQLの各種オブジェクトへのアクセス権限を付与/剥奪
* ロールへのメンバ資格を付与/剥奪

詳細はPostgreSQL文書の[GRANT](https://www.postgresql.org/docs/15/sql-grant.html)/[REVOKE](https://www.postgresql.org/docs/15/sql-revoke.html)を参照してください。

で、PostgreSQL文書を見ていただけると分かるように、とにかく対象のオブジェクトの種類が多い＆オブジェクトの種類毎に指定可能な権限が異なるので、とっても覚えにくいです。
自分も何年もぽすぐれ使っているのに、未だにPostgreSQL文書を読みながらでないと``GRANT``/``REVOKE``は記述できません・・・

## psqlのタブ補完
PostgreSQLをインストールすると利用可能な、PostgreSQLの対話的ターミナル``psql``は、タブ補完機能が充実していることもあって、アドホックにSQL文を書きたいとき重宝しています。
もちろん、従来から``GRANT/REVOKE``文に対するタブ補完機能はありましたが、PostgreSQLでもタブ補完機能が更に改善されました。

# 変更内容

## GRANTコマンドタグのみの状態

### PostgreSQL 15
PostgreSQL 15.0では以下のように補完候補がでてきます。[^1]

```sql
=# GRANT
ALL                        pg_checkpoint              pg_signal_backend          TEMPORARY
ALTER SYSTEM               pg_database_owner          pg_stat_scan_tables        testdb_owner
CONNECT                    pg_execute_server_program  pg_write_all_data          TRIGGER
CREATE                     pg_monitor                 pg_write_server_files      TRUNCATE
DELETE                     pg_read_all_data           postgres                   UPDATE
EXECUTE                    pg_read_all_settings       REFERENCES                 USAGE
GRANT                      pg_read_all_stats          SELECT
INSERT                     pg_read_server_files       SET
=# GRANT
```

さて、ここで補完されるキーワードに不適切なものが実はあります。
そう、``GRANT``というキーワードが補完候補として出力されています。
PostgreSQLでは、``GRANT GRANT ``というキーワードの並びは不適切です。たぶん、これは、``REVOKE``コマンドのみ存在する
```sql
REVOKE [ GRANT OPTION FOR ]
    { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
（以下略）
```
省略可能な``GRANT OPTION FOR``の``GRANT``が誤って``GRANT``コマンドにも補完候補として現れているのでしょう。

### PostgreSQL 16
PostgreSQL 16では、``GRANT``コマンドタグのみの状態では、``GRANT``キーワードが補完候補に現れないように改善されました。

```sql
=# GRANT
ALL                        pg_analyze_all_tables      pg_read_server_files       SELECT
ALTER SYSTEM               pg_checkpoint              pg_signal_backend          SET
ANALYZE                    pg_database_owner          pg_stat_scan_tables        TEMPORARY
CONNECT                    pg_execute_server_program  pg_vacuum_all_tables       TRIGGER
CREATE                     pg_monitor                 pg_write_all_data          TRUNCATE
DELETE                     pg_read_all_data           pg_write_server_files      UPDATE
EXECUTE                    pg_read_all_settings       postgres                   USAGE
INSERT                     pg_read_all_stats          REFERENCES                 VACUUM
=# GRANT
```

## REVOKE<空白>
また、同じパッチ内で、``REVOKE<空白>``の状態でタブ補完した場合に、``GRANT OPTION FOR``と``ADMIN OPTION FOR``キーワード（どちらも省略可能なので普段は意識しないかもしれませんが・・・）が補完される改造が入っていました。

### PostgreSQL 15

```sql
=# REVOKE
ALL                        pg_checkpoint              pg_signal_backend          TEMPORARY
ALTER SYSTEM               pg_database_owner          pg_stat_scan_tables        testdb_owner
CONNECT                    pg_execute_server_program  pg_write_all_data          TRIGGER
CREATE                     pg_monitor                 pg_write_server_files      TRUNCATE
DELETE                     pg_read_all_data           postgres                   UPDATE
EXECUTE                    pg_read_all_settings       REFERENCES                 USAGE
GRANT                      pg_read_all_stats          SELECT
INSERT                     pg_read_server_files       SET
=# REVOKE
```

### PostgreSQL 16

```sql
=# REVOKE
ADMIN OPTION FOR           INHERIT OPTION FOR         pg_read_all_stats          SELECT
ALL                        INSERT                     pg_read_server_files       SET
ALTER SYSTEM               pg_analyze_all_tables      pg_signal_backend          TEMPORARY
ANALYZE                    pg_checkpoint              pg_stat_scan_tables        TRIGGER
CONNECT                    pg_database_owner          pg_vacuum_all_tables       TRUNCATE
CREATE                     pg_execute_server_program  pg_write_all_data          UPDATE
DELETE                     pg_monitor                 pg_write_server_files      USAGE
EXECUTE                    pg_read_all_data           postgres                   VACUUM
GRANT OPTION FOR           pg_read_all_settings       REFERENCES
=# REVOKE
```

## 他にもあるかもしれないけど
すいません、確認環境を作るのに力尽きたのでこの記事はここまでにします・・・（うまく再現できなかったりして凹んでいる）

## 補足(ANALYZE/VACUUMキーワードの補完)
この記事のために``GRANT``/``REVOKE``のタブ補完の挙動を調べていて気づいたのですが、1日目の記事（[PG16:allow granting VACUUM and ANALYZE privileges on relations](https://qiita.com/nuko_yokohama/items/37b197a6f39edb1278f4)）の改善により、``psql``のタブ補完にも影響があることに気づきました（``GRANT/REVOKE``キーワードの直後にタブ補完すると``ANALYZE``/``VACUUM``キーワードが補完される）。
これについては、1日目の記事に追記しました。

うーん、MLの投稿記事だけでなく、きちんとパッチファイルの中身を確認しないといけないのかな・・・（猫には手に余る・・・）

# おわりに
今回は``psql``のタブ補完のちょっとした改善について書いてみました。こういう細かい改善の積み重ねが``psql``の使い勝手の良さにつながっているのでしょうね。

[^1]:この対処がPostgreSQL 15以前の版に反映されるかどうかは未確認です。ある意味Bug-Fixぽいから反映されるのかな？