2005年3月31日木曜日

Sledge + MySQL4.1でセッションを保存できない

Sledge+MySQL4.1な環境でセッションを保存できないという状況に陥りました。
現象としては、セッションIDは保存されているのに、セッションデータ(a_session)だけが保存されないという状況です。どうやらTEXT型のフィールドにStorableモジュールでnfreezeしたデータを入れることができないみたいなので、原因を調べてみました。。

MySQL リファレンスマニュアル :: 2.5.1 バージョン 4.0 から 4.1 へのアップグレードによると、
>
すべてのテーブルと文字列カラムがキャラクタセットを持つようになった。 See 章 9. 各国キャラクタセットと Unicode。 キャラクタセット情報は、SHOW CREATE TABLE と mysqldump によって表示される (MySQL バージョン 4.0.6 以降は、新しいダンプファイルを読み取ることはできる。これより前のバージョンは、新しいダンプファイルを読み取ることはできない)。
<
ということで、4.1からはTEXT型がキャラクタセットを持つようになったようです。試しにshow create talbe sessionsを実行すると以下のように、CHARSET=ujisがついていました。
>

CREATE TABLE `sessions` (
`id` varchar(32) NOT NULL default '',
`a_session` mediumtext,
`timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=ujis
<

このことから、ujis(EUC)のキャラクタセットをもつTEXTフィールドにnfreezeしたujis以外の文字コードを含んだデータをインサートしようとしたため、データが空になってしまうのではと予想しました。

そこでSledge::Session::Pgにならって、nfreezeしたものをbase64エンコードして、ujisの文字コード内で表現できるデータにしてからインサートするようにしたところ、うまくデータを保存できるようになりました。実際には以下のようなSledge::Session::MySQLのサブクラスを作って、替わりにcreate_sessionにセットしてあげました。
>

package Sledge::Session::MySQL41;
use strict;
use base qw(Sledge::Session::MySQL);

use MIME::Base64;

sub _serialize {
my($self, $data) = @_;
return encode_base64(Storable::freeze($data));
}

sub _deserialize {
my($self, $data) = @_;
return Storable::thaw(decode_base64($data));
}

1;
<

4 件のコメント:

  1. ボクは、textじゃなくて、longblobを使うようにしてました。
    MLに投げようとおもって忘れてた。

    返信削除
  2. きむらさんこんにちは。
    なるほど、セッションデータ自体がバイナリであること考えると、型をlongblob型などに変える方が自然ですね。

    返信削除
  3. あいらも同じはまりをして base64で逃げましたw。
    my.cnfでdefault-charsetを binary にっていう人もいましたけど。。。
    (変換しないという意味で)

    返信削除
  4. binaryにっていうのはちょっと強引な気もしますね。
    やはり、きむらさんのa_sessionの型をblogにするというのが、お手軽だし、まっとうな方法ですかねー。

    返信削除