読者です 読者をやめる 読者になる 読者になる

Ruby/MySQL 2.9

MySQL Ruby

Ruby から MySQL を使うための pure Ruby ライブラリ Ruby/MySQL 2.9 を公開しました。まだベータ版です。 http://github.com/tmtm/ruby-mysql/tree/2.9

前の Ruby/MySQL は 0.2.6 だったのですが、今回 2.9 とした理由は:

  • Cライブラリ版の MySQL/Ruby 2.8.x の後継。
  • 次は 3.0 にしたいという希望。

…という意味があります。

gem は gemcutter にあります。http://gemcutter.org/gems/ruby-mysql/versions/2.9.0
gemcutter が設定されて入れば次のコマンドでインストールできます。

# gem install ruby-mysql -v 2.9

対応する Ruby バージョンは 1.8.7 / 1.9.1 / 1.9.2、MySQL バージョンは 5.1.x です。

MySQL/Ruby 2.8.x との互換

以前のバージョンと異なり、MySQL/Ruby 2.8.x とほぼ互換があります。ただし以下の非互換があります。

Ruby 1.8.x で使用する場合、Mysql#escape_string は、マルチバイト文字の一部として特殊記号を含むマルチバイト文字セットに対して安全ではありませんシフトJIS(sjis, cp932)等は2バイト目に「\」を含むためこの制限にあてはまります。プログラム側で独自にエスケープ処理を行うか、ストアドプロシジャを使用してください。そうでないと SQL インジェクションの危険性がありますEUC-JP や UTF-8 は問題ありません。

いくつかのメソッドがありません: Mysql#debug, Mysql#change_user, Mysql#create_db, Mysql#drop_db, Mysql#dump_debug_info, Mysql#ssl_set, Mysql#reconnect

Mysql#options でサポートしているオプションは次のものだけです: Mysql::INIT_COMMAND, Mysql::OPT_CONNECT_TIMEOUT, Mysql::OPT_LOCAL_INFILE, Mysql::OPT_READ_TIMEOUT, Mysql::OPT_WRITE_TIMEOUT, Mysql::SET_CHARSET_NAME. これら以外を指定すると "option not implementted" という warning が標準エラー出力に出力されます。

Mysql#use_result は Mysql#store_result と同じです。つまりサーバーから一気に結果セットを読み込みます。

MySQL/Ruby 2.8.x からの改良点

Ruby 1.9.x の M17N に対応しています。mysqld へのクエリ文字列やプリペアドステートメントで与える値は mysqld との接続の文字コードに自動的に変換されます。mysqld からの結果文字列は接続文字コードとして取り出されます。

Mysql::Result, Mysql::Stmt が Enumerable を include しています。

ブロックなしの Mysql::Result#each, each_hash Mysql::Stmt#each, each_hash が Enumerator を返します。

Mysql#charset= で接続 charset を指定できます。

Mysql::Error だけでなく、エラー種別ごとにエラークラスが用意されてます。たとえば、構文エラーの場合は Mysql::ParseError など。これらのエラーは Mysql::Error の継承クラスです。

他に pure Ruby 版であることのメリットとして、Ruby のマルチスレッドが同時に動くというのがあります。あるスレッドで時間のかかるクエリを実行中に他のスレッドが動くことができます。

機能的な改良点ではありませんが、ライセンスは Ruby ライセンスです。Cライブラリ版の MySQL/Ruby は libmysqlclient をリンクするため、それを使用する Ruby スクリプトも GPL にするか、それが嫌なら MySQL の商用ライセンスを購入する必要がありました。Ruby/MySQL は libmysqlclient をリンクしないため、その制限はありません。

Ruby 1.9.x M17N 対応

MySQL はデータベース、テーブル、カラム毎にそれぞれ文字セットを持っています。また、サーバーとクライアントの間の接続に文字セットを持っています。接続とカラムとの間の文字セットは MySQL のサーバー側で自動的に変換されます。

Ruby/MySQL では MySQL 接続の文字セットを Mysql#charset= で指定できます。または、Mysql#connect 前に Mysql#options(Mysql::SET_CHARSET_NAME) で設定します。

Ruby 1.9.x では文字列はそれぞれエンコーディング(文字セット)を持っています。Ruby/MySQLRuby プログラムから MySQL サーバーに渡す文字列(クエリ文字列や、プリペアドステートメントのパラメータ)は自動的に接続に応じた文字セットに変換されます。

MySQL サーバーから返される文字列の Rubyエンコーディングは接続の文字セットに対応したものになります。ただし、プリペアドステートメントでは、BINARY型とBIT型のデータは ASCII-8BIT エンコーディングで返ります。

例:

# -*- coding:utf-8 -*-
require 'mysql'
my = Mysql.connect(nil, 'username', 'password')
my.charset = 'cp932'          # 接続の文字セットは CP932
query = 'select "あいう"'     # UTF-8 のクエリ文字列
query.encoding                # => #<Encoding:UTF-8>
col, = my.query(query).fetch  # 取り出した値は接続と同じく CP932
col.encoding                  # => #<Encoding:Windows-31J>
col                           # => CP932 で "あいう"