Ruby mysql2の動作でよくわからないところ
Ruby mysql2でqueryとprepareで動作が違う。これが仕様なのかどうなのかわからない。
バージョン
ruby : ruby 2.1.1.p76
mysql2 : 0.5.2
準備
検証用テーブルを作成。
create.sql
CREATE TABLE t_test (
no int(11) DEFAULT NULL,
test_date date DEFAULT NULL,
article varchar(256) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
;
検証用データを挿入。
insert into t_test values
('1',now(),'date on'),
('2',null,'date null'),
('3','0000-00-00','date space')
;
データ確認
mysql> select * from t_test ;
+------+------------+------------+
| no | test_date | article |
+------+------------+------------+
| 1 | 2019-07-01 | date on |
| 2 | NULL | date null |
| 3 | 0000-00-00 | date space |
+------+------------+------------+
3 rows in set (0.00 sec)
mysql> select * from t_test where test_date is null;
+------+-----------+-----------+
| no | test_date | article |
+------+-----------+-----------+
| 2 | NULL | date null |
+------+-----------+-----------+
1 row in set (0.00 sec)
mysql> select * from t_test where test_date <> '0000-00-00';
+------+------------+------------+
| no | test_date | article |
+------+------------+------------+
| 1 | 2019-07-01 | date on |
+------+------------+------------+
1 row in set (0.00 sec)
ま、当たり前の結果。
Rubyからデータを取得してみる。
queryで抽出してみる。
mysql2_query.rb
#! /usr/local/bin/ruby
require 'mysql2'
require 'pp'
cli = Mysql2::Client.new(:host => '127.0.0.1', :username => '***', :password => '***', :database => '***' ,:encoding => 'utf8')
sql1 = %{select no,test_date,article from t_test limit 10}
ret1 = cli.query(sql1 ,:symbolize_keys => true)
ret1.each do |row|
p row
end
queryでデータを呼び出すと普通に出力される。
[anno@sv1]~/bin% ./mysql2_query.rb
{:no=>1, :test_date=>#<Date: 2019-07-01 ((2458666j,0s,0n),+0s,2299161j)>, :article=>"date on"}
{:no=>2, :test_date=>nil, :article=>"date null"}
{:no=>3, :test_date=>nil, :article=>"date space"}
[anno@sv1]~/bin%
prepare + executeで抽出してみる。
mysql2_prepare_1.rb
#! /usr/local/bin/ruby
require 'mysql2'
require 'pp'
cli = Mysql2::Client.new(:host => '127.0.0.1', :username => '***', :password => '***', :database => '***' ,:encoding => 'utf8')
sql2 = %{select no,test_date,article from t_test limit ?}
stmt = cli.prepare(sql2)
ret2 = stmt.execute('10' ,:symbolize_keys => true)
ret2.each do |row|
p row
end
[anno@sv1]~/bin% ./mysql2_prepare_1.rb
/usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:7:in `new': invalid date (ArgumentError)
from /usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:7:in `each'
from /usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:7:in `_execute'
from /usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:7:in `block in execute'
from /usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:6:in `handle_interrupt'
from /usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:6:in `execute'
from ./mysql2_prepare_1.rb:18:in `<main>'
[anno@sv1]~/bin%
prepareでデータを呼び出すとエラーが出る。invalid date???
prepare + executeで抽出してみる(その2)。
dateでエラーとのことなので、日付がnullのデータを排除してselectしてみると成功。
mysql2_prepare_2.rb
#! /usr/local/bin/ruby
require 'mysql2'
require 'pp'
cli = Mysql2::Client.new(:host => '127.0.0.1', :username => '***', :password => '***', :database => '***' ,:encoding => 'utf8')
sql2 = %{select no,test_date,article from t_test where test_date <> '0000-00-00' limit ?}
stmt = cli.prepare(sql2)
ret2 = stmt.execute('10' ,:symbolize_keys => true)
ret2.each do |row|
p row
end
[anno@sv1]~/bin% ./mysql2_prepare_2.rb
{:no=>1, :test_date=>#<Date: 2019-07-01 ((2458666j,0s,0n),+0s,2299161j)>, :article=>"date on"}
[anno@sv1]~/bin%
結論
理由はわからないけど、prepareでデータ抽出をするときは日付データがnullは許容されないらしい。
- SQL側で文字列に変化させてからデータ抽出をする
- prepareをあきらめてqueryで抽出する
- テーブル構造で日付にnull,0000-00-00を許容しない様子にする。 どれかで対処する。