Ruby mysql2 で prepareする際の注意点

# 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で抽出してみる（その２）。
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を許容しない様子にする。
どれかで対処する。