[go: up one dir, main page]
More Web Proxy on the site http://driver.im/

GA

ラベル 5.6 の投稿を表示しています。 すべての投稿を表示
ラベル 5.6 の投稿を表示しています。 すべての投稿を表示

2022/12/14

Re: MySQL 5.6.9のmysqlクライアントがujis, sjis, cp932で落ちる(5.6.12で修正)

この記事は MySQL闇歴史のカレンダー | Advent Calendar 2022 の2枚目の14日目の記事です。TL;DR

知名度:★☆☆☆☆
(俺の心の)闇度 :★★★★☆
UTF-8以外はやめた方が良いよ度:★★★★★


古いやつでも Docker Hub から持ってこられるかなと思ったら、5.6は5.6.25とそれ以降しかなかった(´・ω・`)

仕方ないのでアーカイブから引っ張ってきて展開。

# wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.6.10-linux-glibc2.5-x86_64.tar.gz
# tar xf mysql-5.6.10-linux-glibc2.5-x86_64.tar.gz
# mv -i mysql-5.6.10-linux-glibc2.5-x86_64/ /usr/local/mysql
# cd /usr/local/mysql
# useradd mysql
# ./scripts/mysql_install_db --user=mysql
# ./support-files/mysql.server start
# bin/mysql --default-character-set=ujis
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.6.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
mysql> status;
Segmentation fault (core dumped)

御覧の通り(?)、MySQL 5.6.11とそれ以前では --default-character-set=ujis (sjisでも)で何かを打ち込むと「 mysql コマンドラインクライアントが」クラッシュする。

# file core.230
core.230: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from 'bin/mysql --default-character-set=ujis', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: 'bin/mysql', platform: 'x86_64'

ちゃんとコマンドラインクライアントのコアファイル。

このクラッシュが何故なのかは(もう直ってるし)どうでも良いにせよ、これで生まれた心の闇はこんな感じ

  • Release Candidateだけど落ちたorz
  • 最初のGeneral Availability(5.6.10)では直らなかった
  • ujis, sjisなんて世界から見れば小さなもんで、それ用にテストされているなんて期待はできない

ちなみにこの時期2013年1月というのは この会社 に勤め始めてちょっとの時期だったので、5.6を新規導入しようと色々調べていた時期だったんだろうなあと思います(その更に前の職の時だったような気もしたんだけど気のせいだったようだ…)

まあそうなんだよなと理解はできるんですが、日本人ユーザーとしてはちょっともんにょりした過去のバグなのでした!

2021/09/15

MySQL 5.6とそれ以前は「testデータベースを消せば良いってもんじゃない」というはなし

TL;DR
  • MySQL 5.6とそれ以前のはなし。5.7とそれ以降はこの初期設定は入っていない。

    • MySQL 5.6でもインストール方法によっては存在しないし mysql_secure_installation を使った場合はこの設定は消されるし、MySQL 5.7とそれ以降だろうと5.6からインプレースアップグレードやmysqlスキーマまで含めたフルリストアでアップグレードした場合は設定は残っているだろう
  • 昔のMySQLは test というスキーマを mysql_install_db で作ってしまって、しかもこのスキーマは全アカウントに対して(ストアド以外の)読み書き権限がある

    • GRANT USAGE しかないアカウントでも平気で CREATE TABLEINSERT も一通りできる

    • ついでに言うと test スキーマだけじゃなくて test_1 スキーマにも同じことができる。 test_* のパターンを持つスキーマなら全部そう

  • DROP DATABASE test したところで、誰にでも CREATE DATABASE test する権限があるので、そんなことより権限を剥がす方が先

    • DELETE mysql.db WHERE user = '' AND host = '%'; FLUSH PRIVILEGES; かな

MySQL 5.6は2021/2/1で EOL になっているので、そもそも使わない方が良いだろうし、今日日の5.6とそれ以前限定の話をするのもどうかなとは思っている。が、アップグレードの仕方によってはこの設定は残っているので注意。

取り敢えず、5.6.51の吊るしの mysql_install_db でdatadirを初期化する。


$ ./scripts/mysql_install_db --datadir=/usr/mysql/5.6.51/data

Installing MySQL system tables...2021-09-15 15:11:03 0 [Note] Ignoring --secure-file-priv value as server is running with --bootstrap.

2021-09-15 15:11:03 0 [Note] ./bin/mysqld (mysqld 5.6.51-log) starting as process 4634 ...

OK

Filling help tables...2021-09-15 15:11:05 0 [Note] Ignoring --secure-file-priv value as server is running with --bootstrap.

2021-09-15 15:11:05 0 [Note] ./bin/mysqld (mysqld 5.6.51-log) starting as process 4666 ...

OK

..

$ mysql56
mysql56> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)

この test スキーマができる。最近5.6とか使わないから久々に見たよ。

mysql56> CREATE USER yoku0825@localhost;
Query OK, 0 rows affected (0.00 sec)

コイツがどう悪いのかを試すために、何も権限を持っていないアカウントを作ってみる。

$ mysql56 -uyoku0825

mysql56> SHOW GRANTS;
+----------------------------------------------+
| Grants for yoku0825@localhost                |
+----------------------------------------------+
| GRANT USAGE ON *.* TO 'yoku0825'@'localhost' |
+----------------------------------------------+
1 row in set (0.01 sec)

mysql56> use test
Database changed

mysql56> CREATE TABLE t1 (num int);
Query OK, 0 rows affected (0.02 sec)

mysql56> SHOW TABLES;
+----------------+
| Tables_in_test |
+----------------+
| t1             |
+----------------+
1 row in set (0.00 sec)

フツーに CREATE TABLE できてしまった。これはいけない?
というか何の権限もないのに、この test スキーマをDROPすることももう一度CREATEすることもできる。

mysql56> DROP DATABASE test;
Query OK, 1 row affected (0.00 sec)

mysql56> CREATE DATABASE test;
Query OK, 1 row affected (0.00 sec)

mysql56> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| test               |
+--------------------+
2 rows in set (0.00 sec)

それどころか、 test_ で始まるスキーマ名なら好きなようにできる。

mysql56> CREATE DATABASE test_yoku0825;
Query OK, 1 row affected (0.00 sec)

mysql56> ALTER DATABASE test_yoku0825 CHARSET utf8mb4;
Query OK, 1 row affected (0.00 sec)

mysql56> SHOW CREATE DATABASE test_yoku0825;
+---------------+---------------------------------------------------------------------------+
| Database      | Create Database                                                           |
+---------------+---------------------------------------------------------------------------+
| test_yoku0825 | CREATE DATABASE `test_yoku0825` /*!40100 DEFAULT CHARACTER SET utf8mb4 */ |
+---------------+---------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql56> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| test               |
| test_yoku0825      |
+--------------------+
3 rows in set (0.00 sec)

まれにだがよく(?) 「 test スキーマあるのいけないんで、DROPしてください」みたいな文面があるが、こんなもの消しても何の意味もなくて、この「SHOW GRANTSでは何も見えない何の権限も持っていないはずのアカウントが test スキーマを好きなようにできる」設定の方を何とかしないといけない。

ちなみにこの権限の根源は mysql.db テーブルにある。rootでログインしなおしてクエリーたたいてみる。

mysql56> SELECT * FROM mysql.db;
+------+---------+------+-------------+-------------+-------------+-------------+-------------+-----------+------------+-----------------+------------+------------+-----------------------+------------------+------------------+----------------+---------------------+--------------------+--------------+------------+--------------+
| Host | Db      | User | Select_priv | Insert_priv | Update_priv | Delete_priv | Create_priv | Drop_priv | Grant_priv | References_priv | Index_priv | Alter_priv | Create_tmp_table_priv | Lock_tables_priv | Create_view_priv | Show_view_priv | Create_routine_priv | Alter_routine_priv | Execute_priv | Event_priv | Trigger_priv |
+------+---------+------+-------------+-------------+-------------+-------------+-------------+-----------+------------+-----------------+------------+------------+-----------------------+------------------+------------------+----------------+---------------------+--------------------+--------------+------------+--------------+
| %    | test    |      | Y           | Y           | Y           | Y           | Y           | Y         | N          | Y               | Y          | Y          | Y                     | Y                | Y                | Y              | Y                   | N                  | N            | Y          | Y            |
| %    | test\_% |      | Y           | Y           | Y           | Y           | Y           | Y         | N          | Y               | Y          | Y          | Y                     | Y                | Y                | Y              | Y                   | N                  | N            | Y          | Y            |
+------+---------+------+-------------+-------------+-------------+-------------+-------------+-----------+------------+-----------------+------------+------------+-----------------------+------------------+------------------+----------------+---------------------+--------------------+--------------+------------+--------------+
2 rows in set (0.00 sec)

空白のuserは「任意のuser」、hostの ‘%’ は任意のホスト。
この2行の設定により、 test スキーマと test_ で始まる任意のスキーマはほとんどのスキーマレベル権限を全アカウントに与えている。

mysql_secure_installation はこの2行を消してから FLUSH PRIVILEGES することでこの権限を消している。

https://github.com/mysql/mysql-server/blob/mysql-5.6.51/scripts/mysql_secure_installation.pl.in#L253

rootで消してから FLUSH PRIVILEGES

mysql56> DELETE FROM mysql.db WHERE user = '' AND host = '%';
Query OK, 2 rows affected (0.00 sec)

mysql56> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

これで期待通りの動きになる。

$ mysql56 -uyoku0825

mysql56> SHOW GRANTS;
+----------------------------------------------+
| Grants for yoku0825@localhost                |
+----------------------------------------------+
| GRANT USAGE ON *.* TO 'yoku0825'@'localhost' |
+----------------------------------------------+
1 row in set (0.00 sec)

mysql56> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
+--------------------+
1 row in set (0.00 sec)

mysql56> use test;
ERROR 1044 (42000): Access denied for user 'yoku0825'@'localhost' to database 'test'

ただし、既存のコネクションは use でカレントデータベースを変えるか再接続しないと権限の変更は有効にはならないので、万全を期すならいったん再起動しておくと完璧だと思う。

2018/10/30

mysql.userテーブルの認証周りのカラムあれこれ

TL;DR
version passwordカラム(CHAR(41) NOT NULL) authentication_stringカラム(TEXT NULL) pluginカラム 認証プラグインの選択
5.0.96 パスワードハッシュ カラムなし カラムなし ダイジェスト長
5.1.73 パスワードハッシュ カラムなし カラムなし ダイジェスト長
5.5.62 パスワードハッシュ 常に空文字 認証プラグイン pluginカラム、空文字列の場合はダイジェスト長
5.6.42 SHA256プラグイン以外のパスワードハッシュ SHA256プラグインの時のパスワードハッシュ 認証プラグイン pluginカラム、空文字列の場合はダイジェスト長
5.7.24 カラムなし パスワードハッシュ 認証プラグイン pluginカラムのみ
8.0.13 カラムなし パスワードハッシュ 認証プラグイン pluginカラムのみ

日々の覚書: MySQL 5.7.6でmysql.userテーブルのパスワードのカラム名がなんか変わった で「MySQL 5.7ではパスワードハッシュが格納されるカラムが password から authentication_string に変更になった」としていたけれど、ちょっと調べてみたらなんかそれなりに歴史的経緯っぽいものがありました。
  • 旧来(MySQL 5.0, 5.1)は2種類の認証プラグイン( mysql_native_password = 俗称41桁ハッシュ、 mysql_old_password = 俗称16桁ハッシュ) があったが、それを識別するための plugin カラムは無く、「クライアントから送られてきたダイジェストの長さ」でどちらのプラグインを使うか決めて password カラムに入っているパスワードハッシュを引き出して使っていた
  • MySQL 5.5から plugin カラムが追加される。これは5.5で「認証プラグインAPI」を解放した時に一緒に実装されたのだと思う。
    • MySQL :: MySQL 5.5 Reference Manual :: 6.5.1 Authentication Plugins
    • たぶん過渡期の例外措置として、 plugin が空文字ならば旧来と同じダイジェストの長さによって mysql_native_passwordmysql_old_password を打ち分ける実装になっている
    • authentication_string カラムも実装されたけど、この時点でこのカラムを使っているっぽい認証プラグインは少なくともコミュニティー版のソースコード上にはない。
  • MySQL 5.6では商用版限定ながら sha256_password プラグインが登場する。
    • MySQL :: MySQL 5.6 Reference Manual :: 6.5.1.4 SHA-256 Pluggable Authentication
      • MySQL 8.0では同じ名前の sha256_password プラグインがコミュニティー版でも使えるようになった。実装まで同じかどうかは知らない。
    • MySQL 8.0の sha256_password プラグインと同じものだとすると、パスワードハッシュが $5$ から始まる66桁になるので、 Password CHAR(41) NOT NULL には入らずAuthentication_string TEXT に入れることになったのかな
      • password カラムの長さを変えるのはリスキーだなって感じで
  • MySQL 8.0では sha256_password と同じく256bitのSHA2を使う cache_sha2_password がデフォルトになるのもあって、この時点までに password カラムがなくなって authentication_string に一本化されるのは確定だっただろうから、ちょっと前倒ししてMySQL 5.7で消すことにしたんじゃないかなと思う。
動作とかの部分はそれなりに調べたけど、経緯の部分は想像しているだけで裏付けとかはないです。

2017/04/20

MySQLのDATETIME型で秒の小数部を扱うときのDEFAULT句

この CREATE TABLE ステートメントは転ける。
mysql57> CREATE TABLE t1 (num INT UNSIGNED NOT NULL, dt DATETIME(3) DEFAULT CURRENT_TIMESTAMP);
ERROR 1067 (42000): Invalid default value for 'dt'
CURRENT_TIMESTAMP関数DATETIME(0)型 を返すので、dtカラムの型である DATETIME(3)型 と合わないからだというわけで、
mysql57> CREATE TABLE t1 (num INT UNSIGNED NOT NULL, dt DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3));
Query OK, 0 rows affected (0.01 sec)

mysql57> SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `num` int(10) unsigned NOT NULL,
  `dt` datetime(3) DEFAULT CURRENT_TIMESTAMP(3)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
これで通る。 なお、 ON UPDATE 句を書いた場合も同じ。
mysql57> CREATE TABLE t2 (num INT UNSIGNED NOT NULL, dt DATETIME(3) ON UPDATE CURRENT_TIMESTAMP);
ERROR 1294 (HY000): Invalid ON UPDATE clause for 'dt' column

mysql57> CREATE TABLE t2 (num INT UNSIGNED NOT NULL, dt DATETIME(3) ON UPDATE CURRENT_TIMESTAMP(3));Query OK, 0 rows affected (0.01 sec)

mysql57> SHOW CREATE TABLE t2\G
*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `num` int(10) unsigned NOT NULL,
  `dt` datetime(3) DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(3)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
とても余談として、CURRENT_TIMESTAMP関数が NOW関数 のシノニムってことは、これひょっとして DEFAULT NOW() でもいけるのでは? と思ったらいけた。しかも昔からだった。
mysql55> CREATE TABLE t1 (num INT UNSIGNED NOT NULL, dt TIMESTAMP DEFAULT NOW()); -- 5.5だからTIMESTAMP型じゃないとデフォルトを受けられない
Query OK, 0 rows affected (0.01 sec)

mysql55> SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `num` int(10) unsigned NOT NULL,
  `dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
ちゃんとCURRENT_TIMESTAMPとして扱われている。 ただし、CURRENT_TIMESTAMPと違ってNOWはかっこは省略できない。
mysql55> SELECT CURRENT_TIMESTAMP;
+---------------------+
| CURRENT_TIMESTAMP   |
+---------------------+
| 2017-04-20 15:07:50 |
+---------------------+
1 row in set (0.00 sec)

mysql55> SELECT CURRENT_TIMESTAMP();
+---------------------+
| CURRENT_TIMESTAMP() |
+---------------------+
| 2017-04-20 15:08:03 |
+---------------------+
1 row in set (0.00 sec)

mysql55> SELECT NOW;
ERROR 1054 (42S22): Unknown column 'NOW' in 'field list'

mysql55> SELECT NOW();
+---------------------+
| NOW()               |
+---------------------+
| 2017-04-20 15:08:15 |
+---------------------+
1 row in set (0.00 sec)

2016/06/21

MySQL 5.7のmysql_upgradeがやたら重い件

日々の覚書: MySQL 5.7のmysql_upgradeは本当にDATETIME型を新しいフォーマットに直してくれるけれど でちょっと触れてるんだけど、DATETIME型(TIME型とTIMESTAMP型もあるけど)には現在2つのフォーマットが合って、

- 5.5とそれ以前のDATETIME型(秒部の小数点数非対応、8バイト、以下 旧DATETIME型)
- 5.6とそれ以降のDATETIME型(秒部の小数点数対応、小数部無しの場合は5バイト、以下DATETIME2型)

で、MySQL 5.7のmysql_upgradeは旧DATETIME型をDATETIME2型にアップグレードしてくれるよ、こいつらはレプリケーションで混ぜるとよろしくないから、これで安心だね、みたいなのが 前に書いた記事 のあらすじ。


と、MySQL 5.6 => 5.7のmysql_upgradeが特に問題にはなっていなかったので気付かなかったんだけれど、ふと気付いたら我らが Chiba.pm@masasuz さんが













というわけで計ってみた。
d2.xlargeインスタンスをスポットで借りてゴニョゴニョ。

テストデータはこんな感じ。

$ perl -MDigest::MD5 -e 'for (my $n= 1; $n <= 100000000; $n++) {printf("%d\t%s\n", $n, Digest::MD5::md5_hex($n));}' > /data/md5
mysql> CREATE TABLE t1 (num serial, val varchar(32) not null, dt datetime not null);
mysql> LOAD DATA INFILE '/data/md5' INTO TABLE t1 (num, val) SET dt = NOW();
$ ll d1/t1.ibd -h
-rw-rw---- 1 mysql mysql 6.9G Jun 21 02:16 d1/t1.ibd


結果はこんな感じ。1回ずつしか計ってないから誤差はあると思う。

from to time メモ
5.5(旧DATETIME) 5.7(DATETIME2) 31:16 5.5のmysqldで作ったデータをそのまま5.7のmysqldで起動してmysql_upgrade
5.5(旧DATETIME) 5.6(旧DATETIME) 00:06 5.5のmysqldで作ったデータをそのまま5.6のmysqldで起動してmysql_upgrade
5.6(旧DATETIME) 5.7(旧DATETIME) 00:16 ↑のデータを5.7のmysqld —avoid-temporal-upgradeで起動してmysql_upgrade
5.6(旧DATETIME) 5.7(DATETIME2) 36:53 ↑↑のデータを5.7のmysql_upgrade
5.6(旧DATETIME) 5.6(DATETIME2) 23:01 ↑↑↑のデータを5.6でALTER TABLE t1 FORCE
5.5(旧DATETIME) 5.6(DATETIME2) 22:37 5.5からmysqldumpして5.6にリストア(ダンプに別途1:31かかってる)
5.6(DATETIME2) 5.7(DATETIME2) 00:11 ↑のデータを5.7へmysql_upgrade



5.5のmysqldで作ったデータをそのまま5.7のmysqldで起動してmysql_upgradeした時のリソースの様子。

$ dstat -tamr 10
  date/time   |usr sys idl wai hiq siq| read  writ| recv  send|  in   out | int   csw | used  buff  cach  free| read  writ
21-06 02:23:44|  5   0  64  30   0   0|   0    19M|   6B    4B|   0     0 |1288  1142 |4895M  109M 24.9G  155M|   0   518
21-06 02:23:54|  6   1  65  29   0   0|   0    21M|   0     0 |   0     0 |1385  1176 |4969M  109M 24.8G  152M|   0   563
21-06 02:25:54|  6   0  64  30   0   0|   0    22M|   0     0 |   0     0 |1402  1194 |5822M  115M 24.0G  157M|   0   580


単にdatadirをコピーしてるだけの間は↓これくらい出ていたので、MySQL側の限界ではある様子。

$ dstat -tamr 10
21-06 03:00:14|  0   0  48  52   0   0| 410B  143M|  81B  606B|   0     0 |3491   594 | 889M 75.6M 24.1G 4991M|0.10  3434
21-06 03:00:24|  0   0  50  49   0   0| 410B  137M|  60B  570B|   0     0 |3366   544 | 926M 75.7M 25.4G 3632M|0.10  3295
21-06 03:00:34|  0   0  52  47   0   0|   0   149M|  79B  607B|   0     0 |3616   579 | 964M 75.7M 26.7G 2239M|   0  3576


30秒だけ pt-ioprofile でI/O状況を見てみたらこんな感じ。

# pt-ioprofile --cell sizes
Tue Jun 21 02:22:59 UTC 2016
Tracing process ID 4076
     total     pwrite      fsync      lseek filename
48041558016   96468992          0 47945089024 /data/mysql/d1/#sql-fec_2.ibd
 136257004  136252928       4076          0 /data/mysql/ib_logfile1
 115982336  115982336          0          0 /data/mysql/ibdata1
         0          0          0          0 /data/mysql/ib_logfile0

テンポラリーな.ibdファイルを作ってるので、テーブルコピーのALTER TABLEがまさに走っているはず。
pt-ioprofileを見るに、ibdファイルそのものよりもInnoDBログファイルに書き込んでいる(そう、テーブルコピーのALTER TABLEは1000行ずつコミットするらしい)ので、innodb_flush_log_at_trx_commit= 0とかすると速くなるかも。