cakephp、mysqlのtinyint型に注意
結論から言うと、cakephp(version = ‘1.2.3.8166′)でmysqlのtinyint型に対してModel->save()によるinsertをする場合、強制的にその型はboolean(結果的には0 or 1)にキャストされます。
これで4時間ぐらいはまった・・・ので、怒りに任せてエントリーw
以下、ハマるポイントの詳細。
気づき
まず、こんなテーブルに対して、
CREATE TABLE comments (
id int(9) NOT NULL auto_increment,
body text,
type tinyint(1) default NULL,
created datetime default NULL,
modified datetime default NULL,
PRIMARY KEY (id)
) ;
ごく普通に新規登録する処理を実装しました。ポイントは**typeカラムがtinyint(1)**なことです。その登録処理はこんな感じ、
(・・・省略・・・)
$this->data['Comment']['type'] = 2;
if (!$this->Comment->save($this->data)) {
// SQLエラー処理
}
(・・・省略・・・)
Commentモデルのtypeには「2」を固定でセットしています。これで、typeカラムに「2」が登録されると思っていたのですが、登録されたデータを見てみると「1」になってました。。。はにゃ?とおもい、実行されるSQLを見てみると、
INSERT INTO comments (body, type, modified, created) VALUES ( ‘コメント内容’,1, ‘2010-01-22 03:17:29′, ‘2010-01-22 03:17:29′)
となっており、typeの値が1になっています。なんで!なんでなのっ!
ということで、ここからがハマリタイム(というか、この辺を意識しないで書けるのがcakephpの特徴なのに・・・うう・・・TT)。
調査
ソースを追いかけ、紆余曲折しながら、分かったことは、どうやら、typeカラムがbooleanとして扱われているということでした。
ソースでいうとこの辺(/cake/libs/model/datasources/dbo/dbo_mysql.phpの496行目らへん)
(・・・省略・・・)
switch ($column) {
case 'boolean':
return $this->boolean((bool)$data);
break;
(・・・省略・・・)
つまり、$this->data[‘Comment’][’type’]に1だろうが2だろうがstring型を入れようが、booleanにキャストされるもんで、結果的に0or1しか入らないわけです。。。
他にもtinyintなカラムはあったんですが、これまで0or1しか登録してなかったので、気づきませんでした。てか、勝手にbooleanにしないで・・・涙。
対策
このtypeカラムには1桁の数値が入る予定だったので、tinyintが使えないならということでsmallintに変えました。変えてから上の登録処理を実施すると、無事期待通りのSQLが実施されました。
再び結論
tinyint型はbooleanとして扱われるぞぉー気をつけろぉーー
あ、ちなみにupdateのときはどうなるかは未検証ですが、おそらくおんなじ結果じゃないかなぁーと思ってます。
冷静になって、同じ現象を検索してみると、やはりありました。
[k]zi.bz:CakePHPトtinyintトboolean
もう一歩さきを調べられており、勉強になりました。