2018年7月25日水曜日

MySQL 8.0でLOAD DATA LOCAL INFILEが "ERROR 1148 (42000): The used command is not allowed with this MySQL version" で失敗する時

TL;DR


吊るしのMySQL 8.0で mysql コマンドラインクライアントから LOAD DATA LOCAL INFILE を実行すると転けます。
mysql80 125> LOAD DATA LOCAL INFILE '/tmp/aaa' INTO TABLE t1;
ERROR 1148 (42000): The used command is not allowed with this MySQL version
LODA DATA LOCAL INFILE を実行するには2つの条件が必要で、
  1. LOAD DATA LOCAL INFILE を実行するコネクションに CLIENT_LOCAL_FILES ケーパビリティー(オプションだと思って)が設定されていること
  2. サーバー側で opt_local_infile が設定されていること
2.mysqldlocal_infile オプションなのでわかりやすい。単にデフォルトが5.7とそれ以前の “1” から8.0では “0” に変わったというだけ。
再起動しなくても SET GLOBALSET PERSIST で設定できる。
mysql80 125> SELECT @@local_infile;
+----------------+
| @@local_infile |
+----------------+
|              0 |
+----------------+
1 row in set (0.00 sec)

mysql80 125> SET PERSIST local_infile= 1;
Query OK, 0 rows affected (0.00 sec)

mysql80 125> SELECT @@local_infile;
+----------------+
| @@local_infile |
+----------------+
|              1 |
+----------------+
1 row in set (0.00 sec)
サーバー側( 2. )だけ満たされていても、コネクションに CLIENT_LOCAL_FILES ケーパビリティー( 1. )はついてないのでやっぱり転ける。
同じエラーなので見分けにくい。
mysql80 125> LOAD DATA LOCAL INFILE '/tmp/aaa' INTO TABLE t1;
ERROR 1148 (42000): The used command is not allowed with this MySQL version
1. が満たされているかどうかをgdbを使わずに確かめる方法が見当たらなかったのだけれど、 mysql コマンドラインクライアントであれば —local-infile オプションを有効にするとこのケーパビリティーのフラグが立つ。ただし接続しながら変えることはできないのでこっちは切断してから再接続する。
$ mysql80 --local-infile=1
mysql80> use d1
mysql80 132> LOAD DATA LOCAL INFILE '/tmp/md5' INTO TABLE t1;
サーバーサイドのlocal_infileとクライアントサイドのlocal_infileがそれぞれ別で、それぞれ暗黙のデフォルトが0になったから両方で指定しないといけないよ、というお話でした
ちなみにConnector/Cなら mysql_real_connect を呼ぶときに client_flagCLIENT_LOCAL_FILESを立てるか、 mysql_optionsMYSQL_OPT_LOCAL_INFILE を有効にしてやればおk。

3 件のコメント :

  1. MySQL8.0.11をローカル環境で利用しています。
    質問なのですが、

    ```
    mysql --local-infile=1 -u root -p mydb;
    ```

    でサーバーに入った時に、--local-infile=1が反映されていなく、
    設定を見てもlocal_infileがOFFのままで、
    `load local data`をしてもエラーになってしまいます。(以下の通り)

    ```
    show global variables like "%infile%";
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | local_infile | OFF |
    +---------------+-------+
    1 row in set (0.00 sec)
    ```

    コマンドラインオプションで有効にできないことと
    この記事で取り扱っていることは関係があるのでしょうか?
    このコマンドラインオプションで`load local data infile`を有効にできなかったため、
    結局MySQLサーバーに入って、以下のように直接変数を書き換えて有効にしたら、
    `load local data infile`が使えるようになりました。
    ```
    set global local_infile=ON;
    ```

    本当にお時間のある時で良いので、ご返答いただけたら幸いです。

    返信削除
  2. 度々失礼いたします。
    コメントしておいて大変申し訳ないのですが、自己解決?しました。
    この記事に関しての理解の確認のようなことをさせていただきたいのですが、

    以下の2つのSQL文により表示されるものが、サーバー側の`opt_local_infile`の設定(記事中の2番の設定)であり、これを変更することでサーバー側の設定ができる。
    ```sql
    select @@local_infile; -- どちらも同じ意味?
    show global varaiables like "%infile%"; -- どちらも同じ意味?
    ```

    terminalからMySQLコマンドラインクライアントに接続する時に付与する
    `--local-infile=1`オプション
    が、CLIENT_LOCAL_FILES ケーパビリティーの設定である。(クライアント側の設定、これを確かめる方法はない?)
    そしてこれら2つの設定がONになっていないと`load data local infile`を行えない。

    という理解でよろしいでしょうか?
    質問を連投してしまい申し訳ないのですが、教えていただければ幸いです。
    長文失礼いたしました。

    返信削除
    返信
    1. こんにちはこんにちは。
      おっしゃっている通りで間違いありません!


      > 以下の2つのSQL文により表示されるものがサーバー側の設定ができる。

      その通りです!


      > terminalからMySQLコマンドラインクライアントに接続する時に(クライアント側の設定、これを確かめる方法はない?)

      その通りです!


      > そしてこれら2つの設定がONになっていないと`load data local infile`を行えない。

      まさにその通りです!

      削除