PostgreSQLに接続するときに使える小技の補足

この記事はマニア向けの補足記事です。

psql service=prod

みたいな接続先の指定方法があるという話を書きました。

note.mu

ところでこれこれどう実装されているんでしょう。psqlのコードの中に、service=prodみたいなコマンドライン引数を解釈するコードがあるんだろうかと思ったけど全然そんなのは見当たらないのです。

psqlのヘルプを見てみましょう。

Usage:
 psql [OPTION]... [DBNAME [USERNAME]]

もし、psqlに適当な引数を渡すと、それはDBNAMEとして解釈されます。

$ psql hello
psql: FATAL:  database "hello" does not exist

同様に、service=prodのような文字列をコマンドライン引数として渡した場合も、psql的にはDBNAMEとして扱われます。そしてこれを解釈するのはlibpqです。libpqにはデータベースに接続するための関数がいくつかありますが、psqlでは8.3の頃はPQsetdbLogin()を使っていました(今はPQconnectdbParams()を使っていますが大体似たような話なので省略します)。

https://www.postgresql.jp/document/11/html/libpq-connect.html#LIBPQ-PQSETDBLOGIN

PGconn *PQsetdbLogin(const char *pghost,
                     const char *pgport,
                     const char *pgoptions,
                     const char *pgtty,
                     const char *dbName,
                     const char *login,
                     const char *pwd);

dbName内に=記号が含まれる場合、または有効な接続URI接頭辞を持つ場合、PQconnectdbに渡された場合とまったく同じ扱いでconninfo文字列として扱われます。 その後残りのパラメータがPQconnectdbParamsの指定のように適用されます。

つまり、PQsetdbLogin()の第五引数dbnameにservice=prodみたいな文字列をわたすことができるということです。そして8.3.0のリリースノートにはこの変更について、psqlの変更としてではなくlibpqの変更として以下のように書いてあります。

PostgreSQL: Release Notes

E.147.3.16. libpq

Interpret the dbName parameter of PQsetdbLogin() as a conninfo string if it contains an equals sign (Andrew)

  • This allows use of conninfo strings in client programs that still use PQsetdbLogin().

いかがでしたか?

今回は8.3.0からpsqlのコマンドのコマンドライン引数にconninfo文字列を渡すことができるようになった変更について調べてみました。そしてその変更はpsqlではなくlibpq側で行われたものだということがわかりました。

最後までお読みいただきありがとうございました!もし気に入っていただけたら5000兆円ください!(テンプレあまりよくわかってない)