Help us understand the problem. What is going on with this article?

RubyのMysql2の各種情報(バージョン情報やオプション)を取得する方法

More than 1 year has passed since last update.

背景

Ruby on Rails 等で MySQLを利用している時、低レイヤーの根深い問題や、よくわからないエラーに遭遇したことはありますでしょうか?

RubyでMySQLを利用する際によく使われるライブラリである Mysql2 では、C拡張を利用して libmysqlclient とリンクし、データベースサーバ上の mysqld に対してアクセスしている都合上、複数の概念に対してのバージョン情報やオプションを扱う必要があります。

これらのバージョン情報は、問題の原因究明に重要であるため、取得方法を知っておくことで、効率的な作業が可能になります。自分が調べる時は勿論、他の人に手伝ってもらう時にも重要なヒントになります。

TL; DR

以下のようなデータを記録しておくと、調査が捗ります。

# Railsの場合の Mysql2::Client のオブジェクトの取得方法の例
client = ActiveRecord::Base.connection.raw_connection
# 自前の場合の Mysql2::Client のオブジェクトの作成方法の例
client = Mysql2::Client.new(host: 'localhost', username: 'root')

puts JSON.pretty_generate(
  'RUBY_DESCRIPTION' =>  RUBY_DESCRIPTION,            # Rubyの詳細
  'Mysql2::VERSION' =>  Mysql2::VERSION,              # gemのバージョン
  'Mysql2::Client#info' => client.info,               # libmysqlclient のバージョン
  'Mysql2::Client#server_info' => client.server_info, # 接続先の MySQL Server のバージョン
)

# 接続に関するオプション (おまけ)
puts JSON.pretty_generate(client.query_options.reject { |k, _v| k == :password })  # 他にも重要な情報はあるが、最低限、パスワードは取り除く

出力例

{
  "RUBY_DESCRIPTION": "ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18]",
  "Mysql2::VERSION": "0.4.10",
  "Mysql2::Client#info": {
    "id": 80016,
    "version": "8.0.16",
    "header_version": "8.0.16"
  },
  "Mysql2::Client#server_info": {
    "id": 50637,
    "version": "5.6.37"
  }
}

各種バージョン

Rubyの詳細情報

ruby -v の詳細が記述されます。

https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_DESCRIPTION.html

gem のバージョン

gem のバージョンは、以下の Mysql2 自体のバージョン Mysql2::VERSION になります。

https://github.com/brianmario/mysql2

コードは以下のような形になっています。

https://github.com/brianmario/mysql2/blob/982dbdb1d521c668547cfd4ab927558c689b8bfd/lib/mysql2/version.rb#L2

module Mysql2
  VERSION = "0.5.3".freeze
end

libmysqlclient のバージョン

Mysql2 は、独自に MySQLサーバ との通信プロトコルを実装しているわけではなく、 MySQLの提供している、Cで書かれたクライアントライブラリを利用してアクセスしています。
この時のライブラリのバージョンによって、微妙な挙動の差異が発生する場合があるので、この情報も重要です。

Mysql2 では、以下のようにC拡張で Mysql2::Client#info が実装されています。

https://github.com/brianmario/mysql2/blob/f8560c551bf1999baf7df43290e8f89471e77af4/ext/mysql2/client.c#L948-L968

  version = rb_str_new2(mysql_get_client_info());

これが呼び出している mysql_get_client_info() が何を返すかは、MySQLのドキュメントに記述されています。

https://dev.mysql.com/doc/refman/5.6/en/mysql-get-client-info.html

Returns a string that represents the MySQL client library version (for example, "5.6.48").

ということで、クライアントライブラリ libmysqlclient のバージョンが返却されます。

接続先の MySQL Server のバージョン

問題が発生した時は、クライアントバージョンは勿論ですが、相手側のサーババージョンも気になるところです。

Mysql2 では、以下のようにC拡張で Mysql2::Client#server_info が実装されています。

https://github.com/brianmario/mysql2/blob/f8560c551bf1999baf7df43290e8f89471e77af4/ext/mysql2/client.c#L970-L994

  server_info = rb_str_new2(mysql_get_server_info(wrapper->client));

これが呼び出している mysql_get_server_info() が何を返すかは、MySQLのドキュメントに記述されています。

https://dev.mysql.com/doc/refman/5.6/en/mysql-get-server-info.html

Returns a string that represents the MySQL server version (for example, "5.6.48").

ということで、接続先の MySQL サーバのバージョンが返却されます。

接続に関するオプション

MySQLのサーバ側で設定されているオプションも勿論大切ですが、各クライアント(コネクション)毎に維持されているオプションも、細かい挙動を知る上では重要になってきます。

Mysql2 では、以下のようにインスタンス変数へのアクセッサーが生やされて、 Mysql2::Client#query_options があるので、それを利用する形が良いと思われます。

※ このアクセッサーにはパスワードを含む情報が格納されているので、情報共有の際には、それをしっかり取り除くことを留意しておいてください。

https://github.com/brianmario/mysql2/blob/98304cbbc0c9a964c833474a06f55c433ec26432/lib/mysql2/client.rb#L3

参考

https://github.com/brianmario/mysql2
https://dev.mysql.com/doc/refman/5.6/en/c-api-server-client-versions.html

aeroastro
元超小型人工衛星エンジニア。今はWebエンジニア。 http://aeroastro.hatenablog.com/
https://twitter.com/NekomimiMaster
dena_coltd
    Delight and Impact the World
https://dena.com/jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away