MySQL 8.0 の LOAD DATA で The used command is not allowed with this MySQL version エラー
TL;DR
- MySQL 8.0 で
LOAD DATA INFILE LOCAL
を利用するには、 - サーバとクライアント両方で
local-infile
パラメータをON
にする必要がある - セキュリティ強化のため、8.0から
LOAD DATA INFILE LOCAL
はデフォルトで無効にされた
MySQL 8.0 で LOAD DATA INFILE LOCAL が通らない
Loading local data is disabled; this must be enabled on both the client and server sides
エラー*1で LOAD DATA INFILE LOCAL
が通らなくなっていた 。
mysql> LOAD DATA LOCAL INFILE 'file.csv' INTO TABLE tbl SET name=@1, created_at=@2; ERROR 3948 (42000): Loading local data is disabled; this must be enabled on both the client and server sides
local-infile パラメータ
MySQL 8.0 で LOAD DATA LOCAL INFILE
は無効化されたようです。
有効にするには、local-infile
を ON
に設定する必要があるようです。
ON
にして試します。
mysql> SET GLOBAL local_infile=on; Query OK, 0 rows affected (0.00 sec) mysql> LOAD DATA LOCAL INFILE 'file.csv' INTO TABLE tbl SET name=@1, created_at=@2; ERROR 3948 (42000): Loading local data is disabled; this must be enabled on both the client and server sides
ダメでした。。。クライアント側でも--local-infile
を有効化しないと、通らないようです。
$ mysql -h my8.local --local-infile=1 mysql> LOAD DATA LOCAL INFILE 'file.csv' INTO TABLE tbl SET name=@1, created_at=@2; Query OK, 2 rows affected, 10 warnings (0.05 sec)
行けました 👍
なぜ、無効化されたのか?
LOAD DATA LOCAL INFILE
がデフォルトで無効化された理由はマニュアルに記載されています。
The transfer of the file from the client host to the server host is initiated by the MySQL server. In theory, a patched server could be built that would tell the client program to transfer a file of the server's choosing rather than the file named by the client in the LOAD DATA statement. Such a server could access any file on the client host to which the client user has read access. (A patched server could in fact reply with a file-transfer request to any statement, not just LOAD DATA LOCAL, so a more fundamental issue is that clients should not connect to untrusted servers.)
https://dev.mysql.com/doc/refman/8.0/en/load-data-local.html
LOAD DATA LOCAL INFILE
ではSQL中でロードするファイル名を指定しているものの、実際は、サーバからクライアントに対して、ロードするファイルを指示する仕組みになっています。
悪意のある(改ざんされた)サーバに対して実行した場合、クライアントが指定したファイルと異なるファイルをサーバが指示して、送信させることが可能になってしまいます。
In a Web environment where the clients are connecting from a Web server, a user could use LOAD DATA LOCAL to read any files that the Web server process has read access to (assuming that a user could run any statement against the SQL server). In this environment, the client with respect to the MySQL server actually is the Web server, not a remote program being run by users who connect to the Web server.
もう1つ理由が述べられてます。
任意のSQLを実行できるようなWebアプリケーションを実装していた場合、LOAD DATA INFILE LOCAL
を使って、任意のWebサーバ上のファイルを読み取ることが可能になってしまう。
例えば、SQLインジェクションの脆弱性があった場合、DBのデータを操作されてしまうだけでなく、Webサーバ上のファイルの読み取りも許してしまうことに繋がってしまうということですね。
LOAD DATA INFILE LOCAL
は セキュリティ上のリスクになる可能性があるということで、デフォルトで無効化されたことがわかりました。
使い続ける場合は、リスクを理解した上で利用する必要がありそうです。
MySQL 8.0 Authentication requires secure connection エラーの件
MySQL 8.0 から デフォルトのパスワードの仕組みが caching_sha2_password
に変更されました。
これに関連して、yoku0825 さんが以下のエントリーを掲載してます。
yokuさんのエントリーを抜粋すると:
この条件にすべて合致しているとログインが転けて↑のエラーを食らう。
試します
挙動をおさらいします。
サーバ側で FLUSH PRIVILEGES
を実行しSHA2キャッシュをクリアしたあと、SSLを無効化して接続します。
確かに、Authentication requires secure connection.
とエラーが出て、接続できません。
$ mysql -uuser -h my8.local --ssl-mode=DISABLED ERROR 2061 (HY000): Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.
次に、--get-server-public-key
をつけます。このオプションはサーバの公開鍵を自動でクライアントに持ってくるオプションです。
サーバの公開鍵を使って、パスワードを暗号化し、サーバへ送信し、認証が行われます。
$ mysql -uuser -h my8.local --ssl-mode=DISABLED --get-server-public-key mysql>
一度、接続すれば、SHA2キャッシュが作られるので、以降は--get-server-public-key
を指定しなくても接続できるようになります。
$ mysql -uuser -h my8.local --ssl-mode=DISABLED mysql>
運用への影響を考えてみる
(サーバを再起動したりして) SHA2キャッシュがクリアされたときに、SSLを利用していないクライアントが一斉に接続エラーになっては困ります。 そのようなことが起こり得るか検討してみます。
mysql コマンド
mysql コマンドはデフォルトでSSLを利用します。あえてSSLを無効化しているようなケースはあまりないでしょう。 コマンドラインでMySQLを使っている場合は、心配しなくて良さそうです。
各種、言語ドライバーはどうでしょうか?
mysql コマンドの --get-server-public-key
相当の挙動がドライバ側に実装されていれば、開発者側では特に意識する必要はないということになりますが。。。
ドライバの挙動
PHP 7.4
PHP 7.4 で試します。
<?php try { $pdo = new PDO('mysql:host=my8.local;charset=utf8','user','Password%123'); } catch (PDOException $e) { exit($e->getMessage()); } $stmt = $pdo->query("SHOW STATUS LIKE 'Ssl_cipher'"); print_r($stmt->fetch(PDO::FETCH_ASSOC));
おっ、特にエラーなく接続できた!Ssl_cipherが空なのでSSL無効でエラーなく接続できました。
$ php pdo.php Array ( [Variable_name] => Ssl_cipher [Value] => )
PHP の コミットログをみると、きちんとサーバ側の公開鍵を自動で取ってくる実装が追加されていそうです👏
https://github.com/php/php-src/commit/d6e81f0bfd0cb90586dd83d4fd47a4302605261a
PHP7.3
PHP 7.3 でも試します。
$ php pdo.php SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client
そもそも、caching_sha2_password
がサポートされてないようですね 😢
MySQL 8 を使うには PHP7.4 以降を利用する必要があることがわかりました。
node.js
var mysql = require('mysql'); var con = mysql.createConnection({ host: "my8.local", user: "user", password: "Password%123" }); con.connect(function(err) { if (err) throw err; console.log("Connected!"); }); // simple query con.query( "SHOW STATUS LIKE 'Ssl_cipher'", function(err, results, fields) { console.log(results); } );
node.js の mysql もまだ caching_sha2_password
をサポートしてないようですね。。。。
$ node mysql.js /home/mita2/nodejs-conn/node_modules/mysql/lib/protocol/Parser.js:437 throw err; // Rethrow non-MySQL errors ^ Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client
PRは出ているのですが、まだ、取り込まれてないようです。 https://github.com/mysqljs/mysql/pull/2233
mysql2 のほうには取り込まれているようなので、mysql2 を試します。
mysql
と mysql2
は互換性があります。ドライバを差し替えるにはvar mysql = require('mysql');
を var mysql = require('mysql2');
にするだけです。
$ node mysql.js Connected! [ TextRow { Variable_name: 'Ssl_cipher', Value: '' } ]
大丈夫そうです😄
まとめ
- PHPは 7.4 以上なら大丈夫!
- Node.js のドライバは mysql2 なら大丈夫!
MySQL 8.0 の binlog_row_metadata オプションを試す
TL;DR
- MySQL 8.0 で導入された binlog_row_metadata について調べた
- 今のところデータ連携用途以外では使うところはなさそう
binlog_row_metadata オプションとは何か
マニュアルでは以下のように記載されています。
- デフォルトはMINIMAL(最小限)
- ROWベースのみ有効
- MINIMALでは、SIGNEDフラグ、カラムの文字コードセット、Geometoryタイプのみをバイナリログに記録する。
Configures the amount of table metadata added to the binary log when using row-based logging. When set to MINIMAL, the default, only metadata related to SIGNED flags, column character set and geometry types are logged. When set to FULL complete metadata for tables is logged, such as column name, ENUM or SET string values, PRIMARY KEY information, and so on. https://dev.mysql.com/doc/refman/8.0/en/replication-options-binary-log.html#sysvar_binlog_row_metadata
実際にMINIMALとFULLで比較してみます。
メタデータは mysqlbinlog
コマンドに --print-table-metadata
オプションを指定し、確認します。
テスト用のテーブル:
mysql> DESC t.bin_meta_t; +-------+---------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+---------------------+------+-----+---------+----------------+ | pk | bigint(20) unsigned | NO | PRI | NULL | auto_increment | | col1 | varchar(255) | YES | | NULL | | +-------+---------------------+------+-----+---------+----------------+ 2 rows in set (0.01 sec)
MINIMAL
# mysqlbinlog -vv --print-table-metadata binlog.000009 <snip> # at 306 #191231 16:52:57 server id 1 end_log_pos 367 CRC32 0x99f3c5db Table_map: `t`.`bin_meta_t` mapped to number 93 # Columns(BIGINT UNSIGNED NOT NULL, # VARCHAR(255) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci) # at 367 #191231 16:52:57 server id 1 end_log_pos 425 CRC32 0xd85ee9d6 Write_rows: table id 93 flags: STMT_END_F BINLOG ' Wf4KXhMBAAAAPQAAAG8BAAAAAF0AAAAAAAEAAXQACmJpbl9tZXRhX3QAAggPAvwDAgEBgAID/P8A 28XzmQ== Wf4KXh4BAAAAOgAAAKkBAAAAAF0AAAAAAAEAAgAC/wABAAAAAAAAAAwATUlOSU1BTCBNRVRB1ule 2A== '/*!*/; ### INSERT INTO `t`.`bin_meta_t` ### SET ### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */ ### @2='MINIMAL META' /* VARSTRING(1020) meta=1020 nullable=1 is_null=0 */ # at 425 #191231 16:52:57 server id 1 end_log_pos 456 CRC32 0xaedc614c Xid = 179 <snip>
FULL
# mysqlbinlog -vv --print-table-metadata binlog.000009 <snip> # at 306 #191231 16:53:49 server id 1 end_log_pos 380 CRC32 0xd2360199 Table_map: `t`.`bin_meta_t` mapped to number 93 # Columns(`pk` BIGINT UNSIGNED NOT NULL, # `col1` VARCHAR(255) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci) # Primary Key(pk) # at 380 #191231 16:53:49 server id 1 end_log_pos 435 CRC32 0x5826b7f8 Write_rows: table id 93 flags: STMT_END_F BINLOG ' jf4KXhMBAAAASgAAAHwBAAAAAF0AAAAAAAEAAXQACmJpbl9tZXRhX3QAAggPAvwDAgEBgAID/P8A BAgCcGsEY29sMQgBAJkBNtI= jf4KXh4BAAAANwAAALMBAAAAAF0AAAAAAAEAAgAC/wACAAAAAAAAAAkARlVMTCBNRVRB+LcmWA== '/*!*/; ### INSERT INTO `t`.`bin_meta_t` ### SET ### @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */ ### @2='FULL META' /* VARSTRING(1020) meta=1020 nullable=1 is_null=0 */ # at 435 <snip>
Columns の部分が異なっています。
FULL
の場合は以下のようにカラム名がメタデータに含まれていることが確認できました。また、プライマリキーになっているカラム名も追加されています。MINIMAL
ではカラム名は含まれません。「テーブルの何番目のカラムが変更されたか」のみが記載されています。
# Columns(`pk` BIGINT UNSIGNED NOT NULL, # `col1` VARCHAR(255) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci) # Primary Key(pk)
どういう時に役に立つのか
マニュアルには以下の2つが記載されてます。
1つ目:データ連携がやりやすくなる。データが変更されたカラムの名前がバイナリログを見れば、すぐ判断できるため、データを連携する仕組みがこれまでより用意に実装できるということでしょう。
- External software can use the metadata to decode row events and store the data into external databases, such as a data warehouse.
2つ目:マスターとスレーブで構成が異なるテーブルであってもレプリケーションが可能になるマスターとスレーブでカラムの順番が異なるとかそういうケースを指していると思われる。
- Slaves use the metadata to transfer data when its table structure is different from the master's.
これは実際試してみたのですが、うまく動きませんでした(レプリケーションが普通に止まります)。 Worklogを見ると、「スコープ外」と記載されているので、まだ実装されてないようです。
There is a online DDL solution, which first changes slave's data structure and then change master's data structure. So the table on slave may have more or less columns, different column types and different column orders. If required metadata is logged, then slave can support the online DDL solution better. However, making the applier aware of the additional metadata when applying ROW events is out of this worklog scope.
MySQL の クッキーを焼いた
クッキーを焼く
MySQL の クッキーを焼いた話です。技術的な話は出てきませんw
年末年始は、3D プリンタで遊んでました。 3Dプリンタ扱うのは初めてです。試しに、MySQLのイルカのロゴ(Sakila)のクッキー型を作りました。
Sakila クッキー型の作り方
ネットで適当に拾った画像データをベクトルデータに変換する。 Image2Vector を使いました。
apps.apple.comベクトルデータからゴミを取り除く 変換したベクトルデータ(STL)にはゴミが含まれている場合があります。 ベクトルデータを扱えるドロー系のイラストを扱えるソフトウェアでゴミを削除します。自分は Affinity Designer を使いました。
affinity.serif.com 3. モデリングソフトで3Dに変換して、クッキー型に仕上げる
できあがり
MySQL テストコードを書いてみる
先日、MySQLをソースからビルドする方法を書きました。今日はテストコードについてのエントリーです。 mita2db.hateblo.jp
MySQL のテストコード
mysql-test/suite
ディレクトリ以下にテストコードが記述されています。
5800以上のテストが記述されています。
$ find ~/mysql-8.0.18/mysql-test/suite/ -type f -name '*.test' | wc -l 5854
MySQL 8.0 でも 500以上のテストが追加されたとアピールされてます(スライド11ページ)。MySQLの品質はこのテストコードで担保されているんですね。
www.slideshare.net
テストを実行してみる
ビルドしたディレクトリの mysql-test
ディレクトリ以下に、テストを実行するためのスクリプトが配置されます。
mtr
と mysql-test-run
がそのスクリプトです。どちらも実態は mysql-test-run.pl
で、同じものです。
$ ls -alh total 24K drwxr-xr-x 5 mita2san users 174 Dec 27 11:03 . drwxr-xr-x 32 mita2san users 4.0K Dec 26 17:02 .. drwxr-xr-x 3 mita2san users 87 Dec 26 13:41 CMakeFiles -rw-r--r-- 1 mita2san users 2.5K Dec 26 13:41 cmake_install.cmake -rw-r--r-- 1 mita2san users 295 Dec 21 14:07 CTestTestfile.cmake drwxr-xr-x 3 mita2san users 16 Dec 21 14:07 lib -rw-r--r-- 1 mita2san users 7.8K Dec 26 13:41 Makefile lrwxrwxrwx 1 mita2san users 19 Dec 26 13:40 mtr -> ./mysql-test-run.pl lrwxrwxrwx 1 mita2san users 19 Dec 26 13:40 mysql-test-run -> ./mysql-test-run.pl -rwxr-xr-x 1 mita2san users 252 Dec 21 14:07 mysql-test-run.pl drwxr-xr-x 8 mita2san users 97 Dec 27 11:03 var
このコマンドの引数にテストのファイル名を指定することで、特定のテストだけを実行することができます。 何も引数を指定しなければ全てのテストが実行されます。
$ ls mysql-test/suite/sys_vars/t/ | grep binlog_format binlog_format_basic.test $ ./mtr binlog_format_basic <snip> ============================================================================== TEST NAME RESULT TIME (ms) COMMENT ------------------------------------------------------------------------------ [100%] sys_vars.binlog_format_basic [ pass ] 13 ------------------------------------------------------------------------------ The servers were restarted 0 times The servers were reinitialized 0 times Spent 0.013 of 17 seconds executing testcases Completed: All 1 tests were successful.
binlog_format_basic
はこのようなテストコードです。
performance_schema.global_variables
に binlog_format
の列が存在することを確かめていまいした。
--echo '#---------------------BS_STVARS_002_03----------------------#' ################################################################# # Check if the value in GLOBAL Table matches value in variable # ################################################################# --disable_warnings SELECT @@GLOBAL.binlog_format = VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME='binlog_format'; --enable_warnings --echo 1 Expected
テストを記述してみる
オリジナルのテストを記述してみたいと思います。
mysql-test/suite/
以下に任意のデュレクトリを作成し、その下に t
というディレクトリにテストスクリプトを記述します。
r
にはそのスクリプトの期待される出力を記述します。
SELECTを1回だけ実行するシンプルなテストを記述してみました。
$ cd ../mysql-test/suite/ $ mkdir -p mita2/{t,r} $ touch mita2/r/sample_t.result $ vim mita2/t/sample_t.test SELECT "123"; --echo 123 Expected
実行します。
$ ./mtr sample_t Logging: /home/mita2san/mysql-8.0.18/mysql-test/mysql-test-run.pl sample_t MySQL Version 8.0.18 Checking supported features - Binaries are debug compiled Using 'all' suites Collecting tests Checking leftover processes Removing old var directory Creating var directory '/home/mita2san/mysql-8.0.18/build/mysql-test/var' Installing system database Using parallel: 1 ============================================================================== TEST NAME RESULT TIME (ms) COMMENT ------------------------------------------------------------------------------ [100%] mita2.sample_t [ fail ] Test ended at 2019-12-27 12:20:10 CURRENT_TEST: mita2.sample_t --- /home/mita2san/mysql-8.0.18/mysql-test/suite/mita2/r/sample_t.result 2019-12-27 05:30:37.966983335 +0300 +++ /home/mita2san/mysql-8.0.18/build/mysql-test/var/log/sample_t.reject 2019-12-27 06:20:09.905602126 +0300 @@ -0,0 +1,4 @@ +SELECT "123"; +123 +123 +123 Expected mysqltest: Result length mismatch safe_process[21816]: Child process: 21817, exit: 1 - the logfile can be found in '/home/mita2san/mysql-8.0.18/build/mysql-test/var/log/mita2.sample_t/sample_t.log'
[ fail ]
と、失敗しました。 まだ、r
ディレクトリに 期待する出力結果を記述していないため、失敗と判定されました。
ログディレクトリに実行結果が記録されています。これを r
ディレクトリにコピーします。
$ cat build/mysql-test/var/log/sample_t.reject SELECT "123"; 123 123 123 Expected $ mv build/mysql-test/var/log/sample_t.reject mysql-test/suite/mita2/r/sample_t.result
今度はテストをパスしました。めでたしめでたし。
$ ./mtr sample_t Logging: /home/mita2san/mysql-8.0.18/mysql-test/mysql-test-run.pl sample_t MySQL Version 8.0.18 Checking supported features - Binaries are debug compiled Using 'all' suites Collecting tests Checking leftover processes Removing old var directory Creating var directory '/home/mita2san/mysql-8.0.18/build/mysql-test/var' Installing system database Using parallel: 1 ============================================================================== TEST NAME RESULT TIME (ms) COMMENT ------------------------------------------------------------------------------ [100%] mita2.sample_t [ pass ] 1 ------------------------------------------------------------------------------ The servers were restarted 0 times The servers were reinitialized 0 times Spent 0.001 of 17 seconds executing testcases Completed: All 1 tests were successful.
CentOS7 で MySQL 8.0 をソースからビルドする
yoku0825さんが、CentOS8 で MySQL 8.0 をビルドする記事を書いていました。 CentOS8でもビルドするために、あれこれインストールしないといけないようです。
CentOS7インストール直後の状態では色々足りない
最近のMySQLはビルドに最新の開発ツール(cmakeやgcc)を要求してきます。 EPEL等の追加のリポジトリから、色々インストールしなければビルドできません。
手順を忘れないようにメモしておきたいと思います。
CentOS7 だと cmake時に、以下のようなエラーに出くわします。
まず、cmake が古いと、
$ cmake -DDOWNLOAD_BOOST=1 -DWITH_BOOST=/tmp/boost .. <snip> -- Running cmake version 2.8.12.2 CMake Warning at CMakeLists.txt:43 (MESSAGE): Please use cmake3 rather than cmake on this platform
gccもCentOS7のデフォルトのものだと古いと、
$ cmake3 -DDOWNLOAD_BOOST=1 -DWITH_BOOST=/tmp/boost .. <snip> CMake Error at cmake/os/Linux.cmake:59 (MESSAGE): GCC 5.3 or newer is required (-dumpversion says 4.8.5) Call Stack (most recent call first): CMakeLists.txt:442 (INCLUDE)
openssl-devel, ncurses-devel が必要
$ cmake3 .. <snip> -- Looking for SHA512_DIGEST_LENGTH -- Looking for SHA512_DIGEST_LENGTH - not found -- Cannot find appropriate system libraries for WITH_SSL=system. Make sure you have specified a supported SSL version. Valid options are : system (use the OS openssl library), yes (synonym for system), </path/to/custom/openssl/installation> CMake Error at cmake/ssl.cmake:65 (MESSAGE): Please install the appropriate openssl developer package. Call Stack (most recent call first): cmake/ssl.cmake:293 (FATAL_SSL_NOT_FOUND_ERROR) CMakeLists.txt:1181 (MYSQL_CHECK_SSL)
-- Could NOT find Curses (missing: CURSES_LIBRARY CURSES_INCLUDE_PATH) CMake Error at cmake/readline.cmake:71 (MESSAGE): Curses library not found. Please install appropriate package, remove CMakeCache.txt and rerun cmake.On Debian/Ubuntu, package name is libncurses5-dev, on Redhat and derivates it is ncurses-devel. Call Stack (most recent call first): cmake/readline.cmake:100 (FIND_CURSES) cmake/readline.cmake:194 (MYSQL_USE_BUNDLED_EDITLINE) CMakeLists.txt:1185 (MYSQL_CHECK_EDITLINE)
開発ツールをインストールする
openssl と ncurses は特に追加のリポジトリを必要としません。CentOS7標準のRPMパッケージをインストールするだけです。
$ sudo yum install openssl-devel ncurses-devel
cmakeの バージョン3以上 は CentOS7 のデフォルトのリポジトリにはないため、epel を利用します。
$ sudo yum install epel-release $ sudo yum install --enablerepo='epel' cmake3
同じくgcc 5.3以上もデフォルトのリポジトリに存在しないため、Software Collection から新しめのバージョンのものをインストールします。
$ sudo yum install -y http://mirror.centos.org/centos/7/extras/x86_64/Packages/centos-release-scl-2-3.el7.centos.noarch.rpm http://mirror.centos.org/centos/7/extras/x86_64/Packages/centos-release-scl-rh-2-3.el7.centos.noarch.rpm
追記:8.0.24 で gcc10 でのビルドが推奨されるようになりました。8.0.24 以降をビルドする場合は devtoolset-10 を利用する必要があります。
$ sudo yum install devtoolset-7-gcc* <snip> Dependencies Resolved ================================================================================================================================================================================ Package Arch Version Repository Size ================================================================================================================================================================================ Installing: devtoolset-7-gcc x86_64 7.3.1-5.16.el7 centos-sclo-rh 29 M devtoolset-7-gcc-c++ x86_64 7.3.1-5.16.el7 centos-sclo-rh 11 M devtoolset-7-gcc-gdb-plugin x86_64 7.3.1-5.16.el7 centos-sclo-rh 124 k devtoolset-7-gcc-gfortran x86_64 7.3.1-5.16.el7 centos-sclo-rh 11 M devtoolset-7-gcc-plugin-devel x86_64 7.3.1-5.16.el7 centos-sclo-rh 1.3 M Installing for dependencies: devtoolset-7-binutils x86_64 2.28-11.el7 centos-sclo-rh 5.3 M devtoolset-7-libquadmath-devel x86_64 7.3.1-5.16.el7 centos-sclo-rh 154 k devtoolset-7-libstdc++-devel x86_64 7.3.1-5.16.el7 centos-sclo-rh 2.5 M devtoolset-7-runtime x86_64 7.1-4.el7 centos-sclo-rh 20 k gmp-devel x86_64 1:6.0.0-15.el7 centos-base 181 k libgfortran4 x86_64 8.3.1-2.1.1.el7 centos-base 686 k libmpc-devel x86_64 1.0.1-3.el7 centos-base 32 k libquadmath x86_64 4.8.5-39.el7 centos-base 190 k mpfr-devel x86_64 3.1.1-4.el7 centos-base 68 k scl-utils x86_64 20130529-19.el7 centos-base 24 k Transaction Summary ================================================================================================================================================================================ Install 5 Packages (+10 Dependent packages)
/opt/rh/devtoolset-7
以下にインストールされました。
$ /opt/rh/devtoolset-7/root/bin/gcc -v Using built-in specs. COLLECT_GCC=/opt/rh/devtoolset-7/root/bin/gcc COLLECT_LTO_WRAPPER=/opt/rh/devtoolset-7/root/usr/libexec/gcc/x86_64-redhat-linux/7/lto-wrapper Target: x86_64-redhat-linux Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,lto --prefix=/opt/rh/devtoolset-7/root/usr --mandir=/opt/rh/devtoolset-7/root/usr/share/man --infodir=/opt/rh/devtoolset-7/root/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --enable-plugin --with-linker-hash-style=gnu --enable-initfini-array --with-default-libstdcxx-abi=gcc4-compatible --with-isl=/builddir/build/BUILD/gcc-7.3.1-20180303/obj-x86_64-redhat-linux/isl-install --enable-libmpx --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux Thread model: posix gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)
パスを通すために scl enable
を実行します。
$ scl enable devtoolset-7 bash $ which gcc /opt/rh/devtoolset-7/root/usr/bin/gcc
ビルドする
-j
オプションを付けると並列でコンパイルできて、高速です。しかし、並列だとビルドが途中でコケてしまうんですよね(たぶん、メモリ不足が原因)。
自分は以下のように、コケたら、並列度を落として再実行するようにしてます。
$ cd <mysqlのソースディレクトリ> $ mkdir build; cd build $ cmake3 -DDOWNLOAD_BOOST=1 -DWITH_BOOST=/tmp/boost .. $ make -j 8 || make -j 6 || make -j 4 || make
MySQL ヒストリーに記録されない条件
TL; DR;
*IDENTIFIED*:*PASSWORD*
にマッチしたクエリ、つまりパスワードを含むクエリはヒストリーに記録されない- 環境変数
MYSQL_HISTIGNORE
で記録しないクエリを追加指定できる
ヒストリーに記録されない時がある
mysql
コマンド には履歴機能があります。
Linuxのシェルのように、過去に実行したSQLを上の矢印キーで遡ったり、Ctrl-R でキーワード検索することが出来ます。
時々、ヒストリーに記録されないSQLがあることが気になっていました。 今回はその条件を調べてみました。
ソースから辿ってみる
client/mysql.cc
を読んでいきます。
add_filtered_history()
という関数でヒストリーファイルに追記しています。
ignore_matcher
がヒストリーに残さないものを判定していそうです。
2929 /* Add the given line to mysql history and syslog. */ 2930 static void add_filtered_history(const char *string) { 2931 // line shouldn't be on history ignore list 2932 if (ignore_matcher.is_matching(string, charset_info)) return; 2933 2934 #ifdef HAVE_READLINE 2935 if (!quick && not_in_history(string)) add_history(string); 2936 #endif 2937 2938 if (opt_syslog) add_syslog(string); 2939 }
ignore_matcher
は 以下の箇所で定義されており、HI_DEFAULTS
がデフォルト値です。
そして、 MYSQL_HISTIGNORE
という環境変数でヒストリーに記録しないパターンを追加できることもわかりました。
1349 if (!status.batch) { 1350 // history ignore patterns are initialized to default values 1351 ignore_matcher.add_patterns(HI_DEFAULTS); 1352 1353 /* 1354 Additional patterns may be supplied using either --histignore option or 1355 MYSQL_HISTIGNORE environment variable. If supplied, they'll get appended 1356 to the default patterns. In case both are specified, pattern(s) supplied 1357 using --histignore option will be used. 1358 */ 1359 if (opt_histignore) 1360 ignore_matcher.add_patterns(opt_histignore); 1361 else if (getenv("MYSQL_HISTIGNORE")) 1362 ignore_matcher.add_patterns(getenv("MYSQL_HISTIGNORE"));
HI_DEFAULTS
は以下のように定義されていました。
パスワードが入っているSQLをヒストリーに記録してしまうと、ヒストリーファイルからパスワードが読み取られてしまうリスクがあるため、記録しないということでしょう。
132 /** default set of patterns used for history exclusion filter */ 133 const static std::string HI_DEFAULTS("*IDENTIFIED*:*PASSWORD*");
MYSQL_HISTIGNORE を試してみる
環境変数 MYSQL_HISTIGNORE
で無視する条件を追加してみます。
HIMITSU
を含んだSQLをヒストリーに記録しないようにします。
$ export MYSQL_HISTIGNORE='*HIMITSU*' $ mysql mysql> SELECT 'HOGEHOGE'; +----------+ | HOGEHOGE | +----------+ | HOGEHOGE | +----------+ 1 row in set (0.00 sec) mysql> SELECT 'HIMITSU NO HOGEHOGE'; +---------------------+ | HIMITSU NO HOGEHOGE | +---------------------+ | HIMITSU NO HOGEHOGE | +---------------------+ 1 row in set (0.00 sec)
ちゃんと、HIMITSU NO HOGEHOGE
が無視されて、HOGEHOGE
だけがヒストリーファイルに記録されてました。
$ cat ~/.mysql_history _HiStOrY_V2_ SELECT\040'HOGEHOGE'; exit
マニュアルにも書いてある
ソースから辿りましたが、マニュアルにもちゃんと記載がありました。
mysql ignores for logging purposes statements that match any pattern in the “ignore” list. By default, the pattern list is "IDENTIFIED:PASSWORD", to ignore statements that refer to passwords. Pattern matching is not case-sensitive. Within patterns, two characters are special: https://dev.mysql.com/doc/refman/8.0/en/mysql-logging.html