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マッパー経由で使うだろうから、あまり関係ないでしょうけどね。