mysql_config_editorを使ったログインでもデータベースを指定したい

こちらは以下の環境で実施しています。

```sh
$ mysql --version
mysql  Ver 8.0.21 for Linux on x86_64 (MySQL Community Server - GPL)
```

# mysql_config_editorを使ってログインできるようにする

`MySQL`のログイン時に、毎回律儀にホスト名、データベース名、ユーザー名を指定し、パスワードを打って入っていましたが、これをいちいち指定するのが面倒くさいなと気づきました。

```sh
mysql -h ホスト名 -D データベース名 -u ユーザー名 -p
```

調べてみると、`mysql_config_editor`を使うと、ログイン時にいちいちホスト名やパスワードを打たなくてよくなるらしい、とのことで試してみました[^1]。
[^1]: 本文で使用している引用文は、全て[公式リファレンス](https://dev.mysql.com/doc/refman/8.0/ja/mysql-config-editor.html)からの引用です。

https://dev.mysql.com/doc/refman/8.0/ja/mysql-config-editor.html

> mysql_config_editor ユーティリティでは、.mylogin.cnf という名前の不明瞭化されたログインパスファイルに認証資格証明を格納できます。


`.mylogin.cnf`にログイン情報を格納するも、中身は不明瞭化されているんですね。

特にパスワードって、`-pパスワード`とすると怒られるし、それだとセキュリティにもよくないし、かといって毎回毎回打つのも面倒なので、それを扱いやすくしてくれるのはありがたいです。

> mysql_config_editor は、.mylogin.cnf ファイルを不明瞭化してクリアテキストとして読み取れないようにし、クライアントプログラムによって不明瞭化されていない場合はその内容がメモリー内でのみ使用されるようにします。 このようにして、 **パスワードをクリアテキスト以外の形式でファイルに格納し、後でコマンドラインまたは環境変数で公開しなくても使用できます。**（太字引用者）

（ただし難読なだけで解読はできるようなので、利用時はその点に留意する必要がありそうです...）

https://www.slideshare.net/do_aki/mysql-config-editor


## mysql_config_editorでログイン情報をセットする

というわけで`-G(作成するログインパス)`を`local`に指定し、ホスト名・ユーザー名を指定。`Enter password:`でパスワードを入力すると完了。

```sh
$ mysql_config_editor set -G local -h localhost -u test  -p
Enter password:
```

たしかに`cat .mylogin.cnf`としても何が書いてあるのか分からないです。

```sh
$ cat .mylogin.cnf
J����Xq��8��uv�?G�رr��h� m0�/mi�\2H�њ�MOx�N]0����h �I�c�o
```

`mysql_config_editor print --all`を使って初めて`mysql_config_editor`でセットした接続情報が確認できます（パスワードは伏せ字）。

```sh
$ mysql_config_editor print --all
[local]
user = test
password = *****
host = localhost
```

こうして`mysql`の後に`--login-path=name`をオプションを指定することで簡単にログインが可能になりました。

```sh
$ mysql --login-path=local
```

なお、`--login-path`オプションに指定する`name`は`mysql_config_editor set`の際に`--login-path=name` または`-G name`で指定した`name`になります（今回はlocal）。


# mysql_config_editorを使ったログインでもデータベースを指定したい

さて、前置きが長くなりましたが本題です。

`mysql_config_editor`ではログイン時のデータベースを指定することができません。

```sh
$ mysql_config_editor set -G local -h localhost -u test -D sample -p
mysql_config_editor: [ERROR] mysql_config_editor: unknown option '-D'.
```

現状で指定できるのは「ホスト名」「パスワード」「TCP/IP ポート番号」「Unix ソケットファイル名」「ユーザー名」となっています。

自分の場合は、ログイン時に利用するデータベースは固定だったので、ログインしてからいちいち`USE データベース名;`するのが面倒でした。

そして、「`mysql_config_editor`を使ったログインでもデータベースを指定できないのかー！？」と血眼に探し回る羽目になったので、自戒を込めて記しておきます。

## 1. mysqlコマンドのオプションとして渡す

なんでこのことに気付かなかったのか...。

`mysql_config_editor`はログインパスファイルを書き出すのが役目であり、それを利用するのは`mysql`です。だから`mysql_config_editor`でおこなった設定を`mysql --login-path=name`として利用しているわけなので...普通にオプションとしてデータベース名を渡せばいい...。

```sh
$ mysql --login-path=ログインパス名 -D データベース名
```

## 2. my.cnfでdatabaseを指定しておく
ただ先述の方法では結局ログイン時にデータベースを指定しなければいけない煩わしさがあるので、可能であれば設定ファイルで`database`のデフォルトを設定しておくと楽です。

オプション情報は以下のファイルの順で優先されるようになっています。

```sh
$ mysql --help | grep .cnf
  order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf
```

適宜いずれかの`my.cnf`にて`[client]`の下に`database`の値を追記します。

```cnf:my.cnf
[client]
# デフォルトのデータベース
database=データベース名
```

`MySQL`を再起動し、この設定が反映されると、`mysql --login-path=ログインパス名`とした時も、ログイン後はデフォルトの`database`を選択した状態から始められます[^2]。

[^2]:`World-writable config file 'my.cnfのパス' is ignored.`というエラーが出ている場合は、その`my.cnf`のパーミッションを`644`に変更する必要があります。[参考](https://mimirswell.ggnet.co.jp/blog-166)

ちなみに「補完効かないし、`mysql --login-path=ログインパス名`って書くのも面倒じゃね？」という方は以下蛇足:snake:を参考にしていただければ。

# 【蛇足:snake:】`client`ログインパスを利用する
先の例では`--login-path`に任意の`name`を指定する方法でしたが、この`name`を**client**にしておくと`name`を指定しなくてもログインできます。

```sh
# -Gを指定しないと-G clientとなる
$ mysql_config_editor set -h localhost -u test  -p
Enter password:
# 以下はmysql --login-path=clientということ
$ mysql --login-path=
```

この時、`.mylogin.cnf`の`client`ログインパスを見に行ってログインをするようです。

> 使用するログインパスを明示的に示す **--login-path=*name* オプションを指定しない場合、mysql_config_editor はデフォルトで client ログインパスを操作します。**（太字引用者）


さらに言えば、clientログインパスを設定した場合は`mysql`としただけでclientログインパスを利用してログインができます。

```sh
$ mysql
```

これは以下を利用しています。

-  `.mylogin.cnf`の優先順位はほかのオプションファイルより高い
-  `--login-path`オプションを指定しない場合、デフォルトでは`mysql`クライアントはログインパスファイル、オプションファイルから`[client]`および`[mysql]`グループを読み取る

> クライアントプログラムを起動してサーバーに接続すると、**クライアントは .mylogin.cnf を他のオプションファイルとともに使用します。 その優先順位はほかのオプションファイルより高くなります**が、クライアントのコマンド行で明示的に指定されたオプションよりは低くなります。（太字引用者）

優先順位は、__コマンドのオプション > `.mylogin.cnf` > ほかのオプションファイル__ なのですね。デフォルトで使用したいログインは、`mysql_config_editor`であらかじめ設定しておくのが楽そうです。

## `client`ログインパスとそれ以外のログインパスを併用する場合の注意事項

公式の説明だと、`--login-path=mypath`と指定した場合でも、ログインパスの`[mypath]`だけを見に行くわけではなく、他のオプションファイルも見に行っているようです。結構見に行くところ多いんだなと思いました（小並）。

> 他のオプションファイルから[client]と[mysql]を読み取り、ログインパスファイルから[client]、[mysql]および[mypath]を読み取ります。

ちょっとこの`ログインパスファイルから[client]、[mysql]および[mypath]を読み取ります。`の部分における優先順位が気になって、以下の様に`[mypath]ログインパス`と`[client]ログインパス`を用意してみました。

```sh
$ mysql_config_editor print --all
[client]
user = root
password = *****
host = localhost
[mypath]
user = test
password = *****
host = localhost
```

そして`[mypath]ログインパス`を指定してログインします。

```sh
$ mysql --login-path=mypath
```

ログイン中のユーザーを確認してみると、`[mypath]ログインパス`のユーザーになっていました:smile:
文書の書きぶりからログインパスの優先順位が気になりましたが、ログインパスを指定すれば、それが優先されるようで安心しました。

```sql
mysql> select USER();
+-----------------------------+
| USER()                      |
+-----------------------------+
| test@localhost              |
+-----------------------------+
```
---
...ん？:eyes:


> mysql_config_editor では、ログインパスが作成順にログインパスファイルに追加されるため、__最初により一般的なログインパスを作成し、後でより具体的なパスを作成する必要があります。__（太字引用者）

ここで言う「一般的なログインパス」というのが`clientログインパス`を指していると思われます。
つまり、ログインファイルパスに書き込む順番を **`clientログインパス → その他のログインパス`** にする必要があるということのようです。

試しにログインファイルパスでの並び順を`その他のログインパス → clientログインパス`としてみました。

```sh
$ mysql_config_editor print --all
[mypath]
user = test
password = *****
host = localhost
[client]
user = root
password = *****
host = localhost
```

この状態で`mysql --login-path=mypath`とすると...

```sql
mysql> select USER();
+----------------+
| USER()         |
+----------------+
| root@localhost |
+----------------+
```

`clientログインパス`でのログインになっている！`--login-path=mypath`じゃない！:ghost:

`--login-path=mypath`と指定した場合でも、ログインパスファイルにある`clientログインパス`は見に行くので、後書きの設定がオーバーライドされるようです。

これはちょっと要注意ですね。
`clientログインパス`を用いる場合は、それを最初に設定しておく、それ以外のログインパスは`clientログインパス`の後に設定する、としておくのが良さそうです。

なんだか蛇足:snake:が長くなってしまいましたが要するに、`clientログインパス`を使うとログイン時に`--login-path=ログインパス名`と指定しなくてもよくなるが、**clientログインパスは**すべてのクライアントプログラムによって読み取られるので、他のログインパスと併用する場合も考えて**最初に設定しておこう**、ということでした。