GA

2019/12/24

CentOS 8.0にしたらいくつかのURLに error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small でアクセスできなくなった

TL;DR

$ sudo update-crypto-policies --set LEGACY

CentOS 7.xのVMを壊してしまったのでCentOS 8.xのものにお引越ししていたら
$ curl -I https://www8.cao.go.jp
curl: (35) error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small
こんな風になっていくつかアクセスできないURLが。
こちらをがたぶんそのまんまで、CentOS 8.0で入ってくるのが openssl 1.1.1 だから鍵長が短いのをリジェクトしているっぽい。内閣府さん…(www.cao.go.jpの方はいけるんだけどwww8.cao.go.jpの方がダメだった…)
$ rpm -q openssl
openssl-1.1.1-8.el8.x86_64
どうやってさまよってたどり着いたのか全く覚えていないけど、
を眺めていたら crypt-policies というのが設定できるらしく、これをLEGACYにすれば1024ビットのDHパラメーターでも許してくれるらしい。
$ sudo update-crypto-policies --set LEGACY
Setting system policy to LEGACY
Note: System-wide crypto policies are applied on application start-up.
It is recommended to restart the system for the change of policies
to fully take place.

$ curl -I https://www8.cao.go.jp
HTTP/1.1 200 OK
Date: Tue, 24 Dec 2019 06:45:17 GMT
Server: Apache
X-Frame-Options: SAMEORIGIN
Last-Modified: Tue, 20 Nov 2018 08:06:15 GMT
ETag: "1f10-57b141b87cbc0"
Accept-Ranges: bytes
Content-Length: 7952
Cache-Control: no-store
Expires: Tue, 24 Dec 2019 06:45:17 GMT
Pragma: no-cache
Content-Type: text/html
いったー。
自己責任でどうぞ。

2019/12/23

Twitterの過去のツイート履歴をMySQLに取り込む in 2019

TL;DR

  • 過去のツイート履歴がCSVからJSに変わったっぽい
  • でも大丈夫、俺達には JSON_TABLE関数 があるから

かつてはCSVだったツイート履歴、最近ダウンロードしてみたらJSファイルになっていた。しかもでかい。
$ mkdir work
$ cd work
$ unzip ../twitter-2019-12-20-ce0bbf92f327035a47c135f037e0568f6166df65f5f1011bc9d0bc2b6b9b6c3f.zip
..

$ du -sh .
239M    .

$ ll -h tweet.js
-rwxrwxrwx 1 yoku0825 yoku0825 47M Dec 20 09:00 tweet.js
しかもこのJS、よしなにpretty printされていてグレッパビリティが悪い。
$ head tweet.js
window.YTD.tweet.part0 = [ {
  "retweeted" : false,
  "source" : "<a href=\"https://mobile.twitter.com\" rel=\"nofollow\">Twitter Web App</a>",
  "entities" : {
    "hashtags" : [ ],
    "symbols" : [ ],
    "user_mentions" : [ {
      "name" : "坂井 恵(SAKAI Kei)",
      "screen_name" : "sakaik",
      "indices" : [ "0", "7" ],
今まで通り俺はテキトーにgrepしてtweet_idを引きたいんだ…!
という訳で、このtweet.jsをMySQLに突っ込むことにした。
先頭の window.YTD.tweet.part0 = はJSONとしてはInvalidになるのが目に見えているので、ここはあらかじめ削り取ってしまう。
$ jq . tweet.js > /dev/null
parse error: Invalid numeric literal at line 1, column 23
$ cp -ip tweet.js{,.orig}
$ sed -i 's/window.YTD.tweet.part0 = //' tweet.js
$ jq . tweet.js > /dev/null
取り敢えずMySQLは使い捨てで良いのでMySQL ShellのdeploySandboxInstanceでいっこ起動する。
$ mysqlsh
 MySQL  JS > dba.deploySandboxInstance(3306)
..
 MySQL  JS > \c root@localhost:3306
 MySQL  localhost:3306 ssl  JS > \sql
Switching to SQL mode... Commands end with ;

 MySQL  localhost:3306 ssl  SQL > CREATE DATABASE d1;
Query OK, 1 row affected (0.0291 sec)
取り敢えずガワになる d1 スキーマを作ったあと、せっかくなので util.importJSON を使おうかと思ってJSモードに戻ってから叩いてみる。
 MySQL  localhost:3306 ssl  SQL > \js
Switching to JavaScript mode...

 MySQL  localhost:3306 ssl  JS > util.importJson('./tweet.js')
Util.importJson: An X Protocol session is required for JSON import. (RuntimeError)
Xプロトコルじゃないと使えないらしいので、root@localhost:33060に接続しなおしてもう一度。
 MySQL  localhost:3306 ssl  JS > \c root@localhost:33060

 MySQL  localhost:33060+ ssl  JS > util.importJson('./tweet.js')
Util.importJson: There is no active schema on the current session, the target schema for the import operation must be provided in the options. (RuntimeError)
no active schema ってことは USE d1 的なものを押し込まないといけなさそうだけど、JSモードでやる方法がわからないのでSQLモードで USE d1 してからJSモードに戻る。
わかんなかったSQLでやれるのは良いところなのかも知れない、マイエスキューエルシェル。
 MySQL  localhost:33060+ ssl  JS > \sql use d1
Query OK, 0 rows affected (0.0007 sec)

 MySQL  localhost:33060+ ssl  d1  JS > util.importJson('./tweet.js')
Importing from file "./tweet.js" to collection `d1`.`tweet` in MySQL Server at localhost:33060

Processed 0 bytes in 0 documents in 0.0031 sec (0.00 documents/s)
Total successfully imported documents 0 (0.00 documents/s)
Util.importJson: Input does not start with a JSON object at offset 0 (ArgumentError)
失敗…。
 MySQL  localhost:33060+ ssl  d1  JS > \sql
Switching to SQL mode... Commands end with ;

 MySQL  localhost:33060+ ssl  d1  SQL > SHOW TABLES;
+--------------+
| Tables_in_d1 |
+--------------+
| tweet        |
+--------------+
1 row in set (0.0020 sec)

 MySQL  localhost:33060+ ssl  d1  SQL > DESC tweet;
+-------+---------------+------+-----+---------+------------------+
| Field | Type          | Null | Key | Default | Extra            |
+-------+---------------+------+-----+---------+------------------+
| doc   | json          | YES  |     | NULL    |                  |
| _id   | varbinary(32) | NO   | PRI | NULL    | STORED GENERATED |
+-------+---------------+------+-----+---------+------------------+
2 rows in set (0.0021 sec)

 MySQL  localhost:33060+ ssl  d1  SQL > SELECT * FROM tweet;
Empty set (0.0010 sec)
なんかざっと見た感じ、 _id がgenerated columnでPRIMARY KEY(= NOT NULL)なので、そういうカラムが存在しないとダメな気がする。
ドキュメント を流し読んでも、 _id のカラム名を別のもの(tweet_idにできればいいような気がするのよね) に変える方法がパッと見えなかったのでさっさと諦めてSQLでやることにした。
 MySQL  localhost:33060+ ssl  d1  SQL > DROP TABLE tweet;
Query OK, 0 rows affected (0.0746 sec)

 MySQL  localhost:33060+ ssl  d1  SQL > CREATE TABLE t1_tmp (val LONGTEXT);
Query OK, 0 rows affected (0.1394 sec)

 MySQL  localhost:33060+ ssl  d1  SQL > INSERT INTO t1_tmp SELECT LOAD_FILE('/home/yoku0825/down/work/tweet.js');
Query OK, 1 row affected (0.0223 sec)

Records: 1  Duplicates: 0  Warnings: 0

 MySQL  localhost:33060+ ssl  d1  SQL > SELECT * FROM t1_tmp LIMIT 1\G
*************************** 1. row ***************************
val: NULL
1 row in set (0.0005 sec)
ん、しまった、 secure_file_priv があるから LOAD_FILE がNULLになってる。
 MySQL  localhost:33060+ ssl  d1  SQL > SET GLOBAL secure_file_priv= '';
ERROR: 1238: Variable 'secure_file_priv' is a read only variable

 MySQL  localhost:33060+ ssl  d1  SQL > SET PERSIST_ONLY secure_file_priv= '';
ERROR: 1238: Variable 'secure_file_priv' is a non persistent read only variable
できないのかYO…。
おとなしく my.cnf をいじって secure_file_priv = "" を押し込んで再起動。
 MySQL  localhost:33060+ ssl  d1  SQL > TRUNCATE t1_tmp;
Query OK, 0 rows affected (0.1484 sec)

 MySQL  localhost:33060+ ssl  d1  SQL > INSERT INTO t1_tmp SELECT LOAD_FILE('/home/yoku0825/down/work/tweet.js');
Query OK, 1 row affected (4.8416 sec)

Records: 1  Duplicates: 0  Warnings: 0

 MySQL  localhost:33060+ ssl  d1  SQL > \pager head -1000c
Pager has been set to 'head -1000c'.

 MySQL  localhost:33060+ ssl  d1  SQL > SELECT * FROM t1_tmp\G
*************************** 1. row ***************************
val: [ {
  "retweeted" : false,
  "source" : "<a href=\"https://mobile.twitter.com\" rel=\"nofollow\">Twitter Web App</a>",
  "entities" : {
    "hashtags" : [ ],
    "symbols" : [ ],
    "user_mentions" : [ {
      "name" : "坂井 恵(SAKAI Kei)",
      "screen_name" : "sakaik",
      "indices" : [ "0", "7" ],
      "id_str" : "3677561",
      "id" : "3677561"
    } ],
    "urls" : [ ]
  },
  "display_text_range" : [ "0", "27" ],
  "favorite_count" : "0",
  "in_reply_to_status_id_str" : "1207929574333403136",
  "id_str" : "1207929799047385088",
  "in_reply_to_user_id" : "3677561",
  "truncated" : false,
  "retweet_count" : "0",
  "id" : "1207929799047385088",
  "in_reply_to_status_id" : "1207929574333403136",
  "created_at" : "Fri Dec 20 07:44:41 +0000 2019",
  "favorited" : false,
  "full_text" : "@sakaik なるほどミニ丸の方ですか、見てみます!",
  "lang" : "ja",
  "in_reply_to_screen_name" : "sakaik",
OK、入った。
ここからが本丸、 JSON_TABLE 使う。
JSON_TABLE関数に、既にテーブルに入った値を使いたい時は、 FROM t1_tmp, JSON_TABLE(..) の形式でJOINっぽく書いてやる。
PATHの書き方がつらい感じだけどマニュアル首っ引きでやると
 MySQL  localhost:33060+ ssl  d1  SQL > SELECT tweet_id FROM t1_tmp, JSON_TABLE(val, '$[*]' COLUMNS (tweet_id BIGINT UNSIGNED PATH '$.id')) AS json LIMIT 10;
+---------------------+
| tweet_id            |
+---------------------+
| 1207929799047385088 |
| 1207929689987153920 |
| 1207928245233971200 |
| 1207927537533251584 |
| 1207926165190504448 |
| 1207897765130326016 |
| 1207897362191941632 |
| 1207897143224098819 |
| 1207895949948768257 |
| 1207853754973749249 |
+---------------------+
10 rows in set (1.4292 sec)
よし、あたかもテーブル状に、1ツイートが1行の状態で手に入れられそう。
generated columnでパーツ分けはするとして、生JSONの状態で行に分けられればいいのでJSON_TABLEはこんな感じか。
 MySQL  localhost:33060+ ssl  d1  SQL > SELECT tweet_json FROM t1_tmp, JSON_TABLE(val, '$[*]' COLUMNS (tweet_json JSON PATH '$')) AS json LIMIT 1\G
*************************** 1. row ***************************
tweet_json: {"id": "1207929799047385088", "lang": "ja", "id_str": "1207929799047385088", "source": "<a href=\"https://mobile.twitter.com\" rel=\"nofollow\">Twitter Web App</a>", "entities": {"urls": [], "symbols": [], "hashtags": [], "user_mentions": [{"id": "3677561", "name": "坂井 恵(SAKAI Kei)", "id_str": "3677561", "indices": ["0", "7"], "screen_name": "sakaik"}]}, "favorited": false, "full_text": "@sakaik なるほどミニ丸の方ですか、見てみます!", "retweeted": false, "truncated": false, "created_at": "Fri Dec 20 07:44:41 +0000 2019", "retweet_count": "0", "favorite_count": "0", "display_text_range": ["0", "27"], "in_reply_to_user_id": "3677561", "in_reply_to_status_id": "1207929574333403136", "in_reply_to_screen_name": "sakaik", "in_reply_to_user_id_str": "3677561", "in_reply_to_status_id_str": "1207929574333403136"}
1 row in set (1.8848 sec)
よし、じゃあテーブルに突っ込もう。
 MySQL  localhost:33060+ ssl  d1  SQL > CREATE TABLE t1 (tweet_json JSON);
Query OK, 0 rows affected (0.0843 sec)
 MySQL  localhost:33060+ ssl  d1  SQL > INSERT INTO t1 SELECT tweet_json FROM t1_tmp, JSON_TABLE(val, '$[*]' COLUMNS (tweet_json JSON PATH '$')) AS json;
Query OK, 55925 rows affected (4.3389 sec)

Records: 55925  Duplicates: 0  Warnings: 0
generated columnでテキトーに切り分けていくますよ。
 MySQL  localhost:33060+ ssl  d1  SQL > ALTER TABLE t1 ADD tweet_id BIGINT UNSIGNED AS (tweet_json->>'$.id'),                ADD full_text TEXT AS (tweet_json->>'$.full_text'),                ADD created_at VARCHAR(50) AS (tweet_json->>'$.created_at');
Query OK, 0 rows affected (0.0508 sec)

Records: 0  Duplicates: 0  Warnings: 0
 MySQL  localhost:33060+ ssl  d1  SQL >
 MySQL  localhost:33060+ ssl  d1  SQL >
 MySQL  localhost:33060+ ssl  d1  SQL > SELECT tweet_id, full_text, created_at FROM t1 LIMIT 3;
+---------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
| tweet_id            | full_text                                                                                                                                                                                                  | created_at                     |
+---------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
| 1207929799047385088 | @sakaik なるほどミニ丸の方ですか、見てみます!                                                                                                                                                             | Fri Dec 20 07:44:41 +0000 2019 |
| 1207929689987153920 | @sakaik 違うOS向けのバイナリを動かそうとよく出るやつっぽいので、インストールするパッケージが間違っていないか気になります

RHEL 7.x用のパッケージを無理矢理RHEL 6.xにインストールするとかそんなかんじです! | Fri Dec 20 07:44:14 +0000 2019 |
| 1207928245233971200 | @sakaik パッケージものだとすると、サポート対象外になってglibcのバージョンが引きあがったとかありそうですが

https://t.co/MipGicihkr                                                                         | Fri Dec 20 07:38:30 +0000 2019 |
+---------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------
created_atはDATETIME型にキャストしようとしたらできなかったので取り敢えずVARCHARで我慢するとして、これで取り敢えず今まで通り1行1ツイートでゴニョゴニョできるようになった。
in_reply_to_status_idとか切り出せば、再帰CTEでそのスレッドを辿れるな、とか思いつつ取り敢えずここまで。

2019/12/13

MySQL 8.0時代のSET GLOBALとかSET PERSISTに必要な権限

TL;DR

  • オンライン変更は SYSTEM_VARIABLES_ADMIN 権限。 SUPER は非推奨。
  • SET PERSIST_ONLYSYSTEM_VARIABLES_ADMIN 権限 && PERSIST_RO_VARIABLES_ADMIN 権限

ふとコードを読んでいる時に SET PERSIST_ONLY には SUPER 権限は絡んでなさそうなことに気が付いたので試してみる。
  /* for dynamic variables user needs SUPER_ACL or SYSTEM_VARIABLES_ADMIN */
  if (!static_variable) {
    if (!sctx->check_access(SUPER_ACL) &&
        !(sctx->has_global_grant(STRING_WITH_LEN("SYSTEM_VARIABLES_ADMIN"))
              .first)) {
      my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0),
               "SUPER or SYSTEM_VARIABLES_ADMIN");
      return 1;
    }
  } else {
    /*
     for static variables user needs both SYSTEM_VARIABLES_ADMIN and
     PERSIST_RO_VARIABLES_ADMIN
    */
    if (!(sctx->has_global_grant(STRING_WITH_LEN("SYSTEM_VARIABLES_ADMIN"))
              .first &&
          sctx->has_global_grant(STRING_WITH_LEN("PERSIST_RO_VARIABLES_ADMIN"))
              .first)) {
      my_error(ER_PERSIST_ONLY_ACCESS_DENIED_ERROR, MYF(0),
               "SYSTEM_VARIABLES_ADMIN and PERSIST_RO_VARIABLES_ADMIN");
      return 1;
    }
  }
こういう「なんの権限が必要なの」系は、何も権限のついてないアカウント実際に叩くのが一番検証が楽。
mysql80 100> SHOW GRANTS;
+--------------------------------------+
| Grants for yoku0825@%                |
+--------------------------------------+
| GRANT USAGE ON *.* TO `yoku0825`@`%` |
+--------------------------------------+
1 row in set (0.00 sec)

mysql80 100> SET GLOBAL innodb_buffer_pool_size = 128 * 1024 * 1024;ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER or SYSTEM_VARIABLES_ADMIN privilege(s) for this operation

mysql80 100> SET PERSIST innodb_buffer_pool_size = 128 * 1024 * 1024;ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER or SYSTEM_VARIABLES_ADMIN privilege(s) for this operation

mysql80 100> SET PERSIST_ONLY innodb_buffer_pool_size = 128 * 1024 * 1024;
ERROR 3630 (42000): Access denied; you need SYSTEM_VARIABLES_ADMIN and PERSIST_RO_VARIABLES_ADMIN privileges for this operation
8.0導入の新しい権限の方は、権限違反の時にエラー1227じゃなくて3630になるのね。


コードのコメントには "static variables" とは書いてあるけど、ダイナミック変更可能なやつも PERSIST_ONLY ならこっちを通る。
mysql80 102> SHOW GRANTS;
+--------------------------------------+
| Grants for yoku0825@%                |
+--------------------------------------+
| GRANT SUPER ON *.* TO `yoku0825`@`%` |
+--------------------------------------+
1 row in set (0.00 sec)

mysql80 102> SET GLOBAL innodb_buffer_pool_size = 128 * 1024 * 1024;
Query OK, 0 rows affected (0.00 sec)

mysql80 102> SET PERSIST innodb_buffer_pool_size = 128 * 1024 * 1024;
Query OK, 0 rows affected (0.02 sec)

mysql80 102> SET PERSIST_ONLY innodb_buffer_pool_size = 128 * 1024 * 1024;
ERROR 3630 (42000): Access denied; you need SYSTEM_VARIABLES_ADMIN and PERSIST_RO_VARIABLES_ADMIN privileges for this operation

mysql80 104> SHOW GRANTS;
+-------------------------------------------------------+
| Grants for yoku0825@%                                 |
+-------------------------------------------------------+
| GRANT USAGE ON *.* TO `yoku0825`@`%`                  |
| GRANT SYSTEM_VARIABLES_ADMIN ON *.* TO `yoku0825`@`%` |
+-------------------------------------------------------+
2 rows in set (0.00 sec)

mysql80 104> SET GLOBAL innodb_buffer_pool_size = 128 * 1024 * 1024;
Query OK, 0 rows affected (0.00 sec)

mysql80 104> SET PERSIST innodb_buffer_pool_size = 128 * 1024 * 1024;
Query OK, 0 rows affected (0.00 sec)

mysql80 104> SET PERSIST_ONLY innodb_buffer_pool_size = 128 * 1024 * 1024;
ERROR 3630 (42000): Access denied; you need SYSTEM_VARIABLES_ADMIN and PERSIST_RO_VARIABLES_ADMIN privileges for this operation

mysql80 106> SHOW GRANTS;
+-----------------------------------------------------------+
| Grants for yoku0825@%                                     |
+-----------------------------------------------------------+
| GRANT USAGE ON *.* TO `yoku0825`@`%`                      |
| GRANT PERSIST_RO_VARIABLES_ADMIN ON *.* TO `yoku0825`@`%` |
+-----------------------------------------------------------+
2 rows in set (0.00 sec)

mysql80 106> SET GLOBAL innodb_buffer_pool_size = 128 * 1024 * 1024;
ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER or SYSTEM_VARIABLES_ADMIN privilege(s) for this operation

mysql80 106> SET PERSIST innodb_buffer_pool_size = 128 * 1024 * 1024;
ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER or SYSTEM_VARIABLES_ADMIN privilege(s) for this operation

mysql80 106> SET PERSIST_ONLY innodb_buffer_pool_size = 128 * 1024 * 1024;
ERROR 3630 (42000): Access denied; you need SYSTEM_VARIABLES_ADMIN and PERSIST_RO_VARIABLES_ADMIN privileges for this operation

mysql80 109> SHOW GRANTS;
+----------------------------------------------------------------------------------+
| Grants for yoku0825@%                                                            |
+----------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `yoku0825`@`%`                                             |
| GRANT PERSIST_RO_VARIABLES_ADMIN,SYSTEM_VARIABLES_ADMIN ON *.* TO `yoku0825`@`%` |
+----------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

mysql80 109> SET GLOBAL innodb_buffer_pool_size = 128 * 1024 * 1024;
Query OK, 0 rows affected (0.00 sec)

mysql80 109> SET PERSIST innodb_buffer_pool_size = 128 * 1024 * 1024;
Query OK, 0 rows affected (0.00 sec)

mysql80 109> SET PERSIST_ONLY innodb_buffer_pool_size = 128 * 1024 * 1024;
Query OK, 0 rows affected (0.00 sec)

mysql80 111> SHOW GRANTS;
+-----------------------------------------------------------+
| Grants for yoku0825@%                                     |
+-----------------------------------------------------------+
| GRANT SUPER ON *.* TO `yoku0825`@`%`                      |
| GRANT PERSIST_RO_VARIABLES_ADMIN ON *.* TO `yoku0825`@`%` |
+-----------------------------------------------------------+
2 rows in set (0.00 sec)

mysql80 111> SET GLOBAL innodb_buffer_pool_size = 128 * 1024 * 1024;
Query OK, 0 rows affected (0.00 sec)

mysql80 111> SET PERSIST innodb_buffer_pool_size = 128 * 1024 * 1024;
Query OK, 0 rows affected (0.00 sec)

mysql80 111> SET PERSIST_ONLY innodb_buffer_pool_size = 128 * 1024 * 1024;
ERROR 3630 (42000): Access denied; you need SYSTEM_VARIABLES_ADMIN and PERSIST_RO_VARIABLES_ADMIN privileges for this operation
確かにそうなった。
個人的には SET PERSIST_ONLY だけじゃなくて SET PERSISTSUPER だけでできないようにしてくれると嬉しかったりするけれども。
監視用アカウントに SUPER がついて運用しているとこういう権限分離は嬉しい…。

2019/12/09

MySQL 8.0予約語問題にも使える、performance_schemaからエラーになったクエリーをたたき出す方法

TL;DR

  • events_statements_*テーブルmessage_text カラムにエラーメッセージが入っている
  • MySQL 5.6とそれ以降で使える
    • こんな便利なものに気が付いていなかった…

注意

  • MySQL 5.6では events_statements_history は enabled = ‘NO’ になっているので自分で UPDATE する必要がある
  • 動作自体は説明するより↓を見てもらった方が速いと思う。
    • errors > 0 にしてエラーを返さなかったクエリーは無視
    • warnings > 0 にはしたけど、ワーニングメッセージは mysql_errno にも message_text にも入ってこないのでダメだった。。
予約語を踏み抜いたり、 GROUP BY .. ASC みたいなのはパースエラー( mysql_errno = 1064) で出てくるので、それを知ってるとユニットテストとかと組み合わせて予約語対応も捗るかも知れない。
mysql80 48> SELECT * FROM d1.t1 GROUP BY num ASC;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ASC' at line 1

mysql80 48> SELECT num AS rank FROM d1.t1 GROUP BY num ASC;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'rank FROM d1.t1 GROUP BY num ASC' at line 1

mysql80 48> SELECT thread_id, event_name, sql_text, current_schema, mysql_errno, message_text, errors, warnings FROM performance_schema.events_statements_history WHERE errors > 0 OR warnings > 0;
+-----------+---------------------+------------------------------------------------+----------------+-------------+----------------------------------------------------------------------------------------------------------------------------------+--------+----------+
| thread_id | event_name          | sql_text                                       | current_schema | mysql_errno | message_text                                                                                                                     | errors | warnings |
+-----------+---------------------+------------------------------------------------+----------------+-------------+----------------------------------------------------------------------------------------------------------------------------------+--------+----------+
|       111 | statement/sql/error | SELECT * FROM d1.t1 GROUP BY num ASC           | NULL           |        1064 | You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use |      1 |        0 |
|       111 | statement/sql/error | SELECT num AS rank FROM d1.t1 GROUP BY num ASC | NULL           |        1064 | You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use |      1 |        0 |
+-----------+---------------------+------------------------------------------------+----------------+-------------+----------------------------------------------------------------------------------------------------------------------------------+--------+----------+
2 rows in set (0.00 sec)

2019/12/07

ConoHaの上でひたすらMySQLをビルドする簡単なおしごと in 2019年

この記事は ConoHa Advent Calendar 2019 の7日目の記事です。

去年一昨年三年前 とひたすらConoHa VPS 1GBプランでMySQLをビルドしています。
今年も変わらずビルドをするわけですが、去年と比べてMySQL 5.5系はMySQL 5.5.62のままだったので飛ばします。
MySQL 5.5は2018年12月でSustaining Support期間に入っているので、もう(Security Fixを含め)新しいリリースはないのでしょう。これがサポートが切れるということだ。
今年もサクッと新しいサーバーを立ち上げ…お、CentOSが8.0のがあるのでこれにしよう。
それではLet’s build.
$ wget https://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.46.tar.gz
$ tar xf mysql-5.6.46.tar.gz
$ cd mysql-5.6.46/
$ cmake .
-bash: cmake: command not found
ウッ。8系では dnf でインストールするんですよねおれしってる。
$ sudo dnf install cmake
$ cmake .
..
-- Running cmake version 3.11.4
-- Could NOT find Git (missing: GIT_EXECUTABLE)
CMake Error: CMake was unable to find a build program corresponding to "Unix Makefiles".  CMAKE_MAKE_PROGRAM is not set.  You probably need to select a different build tool.
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage
-- Configuring incomplete, errors occurred!
See also "/home/yoku0825/mysql-5.6.46/CMakeFiles/CMakeOutput.log".
ウッ、 git, make, gcc, g++ あたりがいないせいな気がする。
$ sudo dnf install git make gcc gcc-c++
$ cmake .
..
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:66 (MESSAGE):
  Please install the appropriate openssl developer package.

Call Stack (most recent call first):
  cmake/ssl.cmake:260 (FATAL_SSL_NOT_FOUND_ERROR)
  CMakeLists.txt:482 (MYSQL_CHECK_SSL)

-- Configuring incomplete, errors occurred!
See also "/home/yoku0825/mysql-5.6.46/CMakeFiles/CMakeOutput.log".
See also "/home/yoku0825/mysql-5.6.46/CMakeFiles/CMakeError.log".
最近のMySQLはYaSSLバンドルをやめてOpenSSL一本になったので、 openssl-devel が入ってないとダメ、と。
$ sudo dnf install openssl-devel
$ cmake .
..
CMake Error at cmake/readline.cmake:92 (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:135 (FIND_CURSES)
  cmake/readline.cmake:225 (MYSQL_USE_BUNDLED_EDITLINE)
  CMakeLists.txt:484 (MYSQL_CHECK_EDITLINE)

-- Configuring incomplete, errors occurred!
See also "/home/yoku0825/mysql-5.6.46/CMakeFiles/CMakeOutput.log".
See also "/home/yoku0825/mysql-5.6.46/CMakeFiles/CMakeError.log".
今度は ncurses-devel (毎度転けさせてる気がするこれ)
$ sudo dnf install ncurses-devel
$ cmake .
..
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yoku0825/mysql-5.6.46
よし cmake 終わったので make
$ time make
..
real    24m56.940s
user    21m53.985s
sys     2m38.626s
いやあgccのバージョンが新しくなったせいか、ワーニングいっぱい出る…。
とはいえ無事にビルドも終わった。
$ sudo make install
$ du -sh /usr/local/mysql
1.1G    /usr/local/mysql
これを5.7.28と8.0.18でもやるだけの簡単なおしごと。
$ wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-boost-5.7.28.tar.gz
$ tar xf mysql-boost-5.7.28.tar.gz
$ cd mysql-5.7.28/
$ cmake -DWITH_BOOST=./boost
..
-- Checking for module 'libtirpc'
--   Package 'libtirpc', required by 'virtual:world', not found
CMake Error at cmake/rpc.cmake:76 (MESSAGE):
  Could not find rpc/rpc.h in /usr/include or /usr/include/tirpc
Call Stack (most recent call first):
  rapid/plugin/group_replication/configure.cmake:60 (MYSQL_CHECK_RPC)
  rapid/plugin/group_replication/CMakeLists.txt:25 (INCLUDE)

-- Configuring incomplete, errors occurred!
See also "/home/yoku0825/mysql-5.7.28/CMakeFiles/CMakeOutput.log".
See also "/home/yoku0825/mysql-5.7.28/CMakeFiles/CMakeError.log".
MySQL 5.7とそれ以降はビルドにBoostライブラリの特定のバージョンを要求するので、面倒がないBoost同梱版のソースをダウンロードしてきて指定してやる。
あれ何だこれ、見たことないやつが出た。ライブラリの方を要求してるっぽく見えて、Ncursesと同じでdevelが必要なやつっぽい。
$ sudo dnf install libtirpc
Package libtirpc-1.1.4-3.el8.x86_64 is already installed.

$ sudo dnf install libtirpc-devel
$ cmake -DWITH_BOOST=./boost
..
CMake Error at rapid/plugin/group_replication/rpcgen.cmake:100 (MESSAGE):
  Could not find rpcgen
Call Stack (most recent call first):
  rapid/plugin/group_replication/CMakeLists.txt:36 (INCLUDE)

-- Configuring incomplete, errors occurred!
See also "/home/yoku0825/mysql-5.7.28/CMakeFiles/CMakeOutput.log".
See also "/home/yoku0825/mysql-5.7.28/CMakeFiles/CMakeError.log".
ん-。色々新しく必要になるものが増えたのか、CentOS 7と8の違いなのかよくわからん。
$ sudo dnf --enablerepo=PowerTools install rpcgen
$ cmake -DWITH_BOOST=./boost
..
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yoku0825/mysql-5.7.28
cmakeできたのでmake。
$ time make
..
real    67m32.487s
user    50m14.800s
sys     6m39.203s

$ sudo make install
$ du -sh /usr/local/mysql
2.3G    /usr/local/mysql
最後はMySQL 8.0.18。
$ wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-8.0.18.tar.gz
$ tar xf mysql-boost-8.0.18.tar.gz
$ cd mysql-8.0.18/
$ cmake -DWITH_BOOST=./boost
..
CMake Error at CMakeLists.txt:341 (MESSAGE):
  Please do not build in-source.  Out-of source builds are highly
  recommended: you can have multiple builds for the same source, and there is
  an easy way to do cleanup, simply remove the build directory (note that
  'make clean' or 'make distclean' does *not* work)

  You *can* force in-source build by invoking cmake with
  -DFORCE_INSOURCE_BUILD=1

-- Configuring incomplete, errors occurred!
See also "/home/yoku0825/mysql-8.0.18/CMakeFiles/CMakeOutput.log".
あ、そうか、8.0はソースディレクトリの外側でビルドしないといけないんだった。
$ cd ..
$ mkdir work
$ cd work
$ cmake -DWITH_BOOST=../mysql-8.0.18/boost ../mysql-8.0.18
..
CMake Error at CMakeLists.txt:341 (MESSAGE):
  Please do not build in-source.  Out-of source builds are highly
  recommended: you can have multiple builds for the same source, and there is
  an easy way to do cleanup, simply remove the build directory (note that
  'make clean' or 'make distclean' does *not* work)

  You *can* force in-source build by invoking cmake with
  -DFORCE_INSOURCE_BUILD=1
あれ、前と同じエラーが出る時はCMakeCache.txtかな。
$ rm ../mysql-8.0.18/CMakeCache.txt
$ cmake -DWITH_BOOST=../mysql-8.0.18/boost ../mysql-8.0.18
..
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yoku0825/work
大正解。
$ time make
..
real    161m15.531s
user    110m1.582s
sys     15m43.989s

$ sudo make install
$ du -sh /usr/local/mysql
2.2G    /usr/local/mysql

8.0.18、更に時間がかかるようになっていた。。
明日は 8mitsu さんです。