cakephp、mysqlのtinyint型に注意

· application

結論から言うと、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

もう一歩さきを調べられており、勉強になりました。

画像未復旧: hatena.gif

関連があるかもしれないエントリー