github に Ruby/MySQL 3.0.0 を置きました。
git にも gem にも慣れてないので試行錯誤でしたが、なんとか置けたようです。
github は gemspec を置いておけば自動的に gem を作ってくれるはずなのですが、罠に嵌まってもがいてました。
GitHub では *.gemspec ファイルのバージョン番号が更新されたときにのみ Gem を生成する。だから *.gemspec を最初に commit & push したときは、Gem が生成されない(バージョン番号が更新されているわけではないから)。まずは *.gemspec ファイルをバージョン 0.0.0 とかで commit & push し、そのあとバージョンを上げて commit & push し直す。
gemspec のバージョンを変更して git push したらちゃんとできました。
次のようにすればインストールできるはずです。
# sudo gem install tmtm-ruby-mysql --source http://gems.github.com
…と言っておいてなんですが、Ruby/MySQL 3.0.0 はアルファ版なので、ヒトバシラー以外は使ってはいけません。
特徴等
Ruby/MySQL は Ruby から MySQL を使用するためのライブラリです。
- MySQL/Ruby と異なり Ruby で書かれているのでコンパイルの必要はありません。
- Ruby ライセンスです。libmysqlclient は使用していないので GPL ライセンスに縛られません。
- Ruby 1.9 の M17N に対応しています。
- Ruby/MySQL 0.x とも MySQL/Ruby 2.x とも互換はありません。
- まともなドキュメントがありません (ぉ
- MySQL/Ruby 2.x よりも遅いです。たぶん。
使用例
Mysql.connect("mysql://user:passwd@server:3306/dbname") do |my| my.query("select col1,col2 from tblname").each do |col1, col2| p col1, col2 end my.query("insert into tblname (col1,col2) values (?,?)", 123, "abc") end
接続
Mysql.new は Mysql オブジェクトを生成するだけでサーバーに接続はしません。Mysql.connect または Mysql#connect を使用してください。
Mysql.connect の引数には上記のようなURI 文字列の他に、URI オブジェクト、Hash 等を使用できます。
# URI文字列 Mysql.connect("mysql://user:passwd@server/dbname") # URIオブジェクト Mysql.connect URI.parse("mysql://user:passwd@server/dbname") # Hash Mysql.connect(:host=>"server", :user=>"user", :password=>"passwd", :db=>"dbname") # 以前の形式 Mysql.connect("server", "user", "passwd", "dbname")
Mysql.new または Mysql.connect にブロックを渡すと、ブロックを抜ける時に自動的に接続を切断します。
クエリ
Mysql#query でクエリを発行します。クエリ文字列が "sel" で始まる場合はプリペアドステートメントとして実行します。(3.0.1で廃止)プリペアドステートメントクエリの結果は MySQL の型に応じた Ruby オブジェクトになります。以前とは異なり文字列だけとは限りません。
my.query("select 123,'abc'").fetch # => [123, "abc"]
また Mysql#query に引数が2つ以上ある場合もプリペアドステートメントとして実行します。
my.query("insert into tblname (col1,col2) values (?,?)", 123, "abc")
もちろん、プリペアドステートメントを明示して実行することもできます。
stmt = my.prepare("select ?,?") stmt.execute 123, "abc" stmt.fetch # => [123, "abc"]
プリペアドステートメントを使用したくない場合は Mysql#simple_query を使用します。クエリの結果は文字列になります。(3.0.1で廃止)
my.simple_query("select 123,'abc'").fetch # => ["123", "abc"]
エラー
MySQL/Ruby 2.x では例外クラスはすべて Mysql::Error で、エラー種別を判定したい場合は、rescue した後、Mysql::Error#errno を見る必要がありました。Ruby/MySQL 3.0 ではエラーの種類毎に例外クラスが存在するので、rescue でエラーを振り分けできます。まあ、今までがひどかったのですけどね。
begin my.query("....") rescue Mysql::DupEntry ... rescue Mysql::ParseError ... rescue Mysql::NoSuchTable ... end
Charset
Ruby 1.9 では文字列の encoding/charset の自動変換を行います。
特に charset を指定しない場合は MySQL サーバー接続時にサーバーから得られた charset(mysqld の default-character-set パラメータ)を Mysql#charset に保持します。
charset を指定するには Mysql#charset= を使用します。
my.charset = "utf8"
クライアントからサーバーに送られるクエリやデータの文字列は、自動的に Mysql#charset に変換されます。また、サーバーからクライアントに送られる文字列は Mysql#charset に対応する Ruby のエンコーディング文字列として返されます。変換できない場合はエラーになります。
mysqld の default-character-set パラメータが latin1 の場合(これは mysqld のデフォルト値です)、次のスクリプトを実行すると Encoding::UndefinedConversionError 例外が発生します。
# -*- coding:utf-8 -*- require "mysql" Mysql.connect(...) do |my| p my.query("select 'あいう'").fetch end
次のように charset を指定すればエラーになりません。なお、Mysql#charset= に指定できる文字列は Ruby のエンコーディング名ではなく、MySQL の charset 名なので "utf-8" ではなく "utf8" です。
# -*- coding:utf-8 -*- require "mysql" Mysql.connect(...) do |my| my.charset = "utf8" p my.query("select 'あいう'").fetch end
サーバーから取り出される文字列はデータベース上の charset に関係なく、Mysql#charset に対応するエンコーディングの Ruby 文字列になります。
たとえば次のようなテーブルとレコードがある場合、
mysql> show create table t\G *************************** 1. row *************************** Table: t Create Table: CREATE TABLE `t` ( `euc` char(10) CHARACTER SET eucjpms DEFAULT NULL, `sjis` char(10) CHARACTER SET cp932 DEFAULT NULL, `utf8` char(10) CHARACTER SET utf8 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 mysql> select euc,hex(euc),sjis,hex(sjis),utf8,hex(utf8) from t\G *************************** 1. row *************************** euc: あいう hex(euc): A4A2A4A4A4A6 sjis: あいう hex(sjis): 82A082A282A4 utf8: あいう hex(utf8): E38182E38184E38186
それぞれのカラムは、異なる charset の文字列が格納されていますが、Ruby から次のように取り出した場合はすべて UTF-8 文字列になります。
# -*- coding:utf-8 -*- require "mysql" Mysql.connect(...) do |my| my.charset = "utf8" rec = my.query("select * from t").fetch rec.each{|c| p c, c.encoding} end
結果:
"あいう" #<Encoding:UTF-8> "あいう" #<Encoding:UTF-8> "あいう" #<Encoding:UTF-8>
なお、BINARY型や BLOB型のデータは charset によらず、そのままのバイト列で取り出せます。Ruby 文字列のエンコードは ASCII-8BIT になります。
おわりに
MySQL/Ruby と比べて遅かったり、非互換があったりしますが、Ruby 1.9 の M17N がちゃんと扱えるのはこれだけなので、Ruby 1.9 な人はこれを使ってみるのもいいと思います。
ただ、上にも書きましたが、まだアルファ版なので、今後非互換な変更が入る可能性もあります。
まあ、フツーの人は Rails とか O/Rマッパー経由で使うだろうから、あまり関係ないでしょうけどね。