YAPC::Hiroshima 2024がいよいよ来月に迫ってきましたね。
追加チケットはまだ間に合うようなので、Perlを触ったことがない人でもかなり楽しそうなトークが盛りだくさんっぽいのでよろしければぜひぜひ…
と宣伝はこの辺にして、
その後今年に入って別の作業をしていて、昨年のCPANモジュールのバージョンアップをした際に発生した問題を3つほど思い出したので、個人的なメモとして置いておきます。
昨年12月の記事
の追記になります。
Encode.pm で iso_2022_jp が使えなくなった問題
某所で古いメール送信処理が残っており、
Unknown encoding 'iso_2022_jp'
というエラーが発生していました。
$ export PERL_ENCODE_DEBUG=1
$ perl -MEncode -E 'say Encode::encode("iso_2022_jp", "hoge")'
delete $Alias{C} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{ascii} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{cyrillic} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{arabic} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{greek} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{hebrew} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{thai} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
eval "\L$1" at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 30.
find_alias(Encode, iso_2022_jp)->name = at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 73.
Unknown encoding 'iso_2022_jp' at -e line 1.
これは Encode
に対応するエイリアスが変わった問題のようで、
以下のように iso_2022_jp
-> iso-2022-jp
と変更することで動作するようになりました。
$ perl -MEncode -E 'say Encode::encode("iso-2022-jp", "hoge")'
delete $Alias{C} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{ascii} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{cyrillic} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{arabic} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{greek} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{hebrew} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
delete $Alias{thai} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
eval "\L$1" at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 30.
find_alias(Encode, iso-2022-jp)->name = at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 73.
delete $Alias{macjapanese} at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 100.
iso-2022-jp => iso-2022-jp at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 61.
find_alias(Encode, iso-2022-jp)->name = iso-2022-jp at /usr/local/perl-5.36/lib/5.36.1/x86_64-linux/Encode/Alias.pm line 73.
hoge
今どきのメールはほとんど UTF-8
になってきてるとは思いますが、そういう時代を感じるのもまた趣がありますねぇ。
Calendar::Simple で開始曜日の仕様が変わっていた件
こちらは某所で使用していたカレンダーの実装で、気がつくと週の開始曜日が日曜から月曜に変更となっていました。
パッと見だとわかりにくいバグ(というか仕様変更)なので、最初なにが起きたのかと思いましたw
旧バージョン : 1.21
$ docker exec app perl -MCalendar::Simple -E 'say $Calendar::Simple::VERSION'
1.21
$ docker exec app perl -MCalendar::Simple -MData::Dumper -E 'say Dumper( @{Calendar::Simple::calendar(8, 2023)}[0] )'
$VAR1 = [
undef,
undef,
1,
2,
3,
4,
5
];
新バージョン : 2.0.1
$ docker compose exec app carton exec -- perl -MCalendar::Simple -E 'say $Calendar::Simple::VERSION'
2.0.1
$ docker compose exec app carton exec -- perl -MCalendar::Simple -MData::Dumper -E 'say Dumper( @{Calendar::Simple::calendar(8, 2023)}[0] )'
$VAR1 = [
undef,
1,
2,
3,
4,
5,
6
];
を見てみると、以下のような記述が。
[2.0.0] 2020-06-22
Changed
- Default week start date is now Monday
元々は日曜開始用のカレンダーでしたが、
新しい 2.0.0 から月曜開始というのがデフォルトになってしまっているようです。
コンストラクタに 0 を指定すると直るようなので、以下のようにして対応しました。
$ docker-compose exec app carton exec -- perl -MCalendar::Simple -MData::Dumper -E 'say Dumper( @{Calendar::Simple::calendar(8, 2023, 0)}[0] )'
$VAR1 = [
undef,
undef,
1,
2,
3,
4,
5
];
できれば互換性を残してほしかったですが、メジャーバージョンが変わるときに深い理由があったんでしょうかねぇ。
DBI で取得したカラムの型が文字列から数値に変わった件
この問題が一番痺れたバグでした。
ととても似た問題です。(内部的には繋がってるかも?)
DBIでDBからあるテーブルのカラム(カラム自体はint)を取得した際、これまで文字列だったものが、数値型に変わってしまっているというものでした。
こんな感じ(簡略化しています)
my $dbh = DBI->connect($dsn, $user, $password);
my $sth = $dbh->prepare(
'SELECT id, page FROM xxxxx WHERE id = ?')
or die "prepare statement failed: $dbh->errstr()";
$sth->execute('57590') or die "execution failed: $dbh->errstr()";
while (my $ref = $sth->fetchrow_hashref()) {
print "Found a row: id = $ref->{'id'}, fn = $ref->{'page'}\n";
warn Dumper($ref);
}
$sth->finish;
旧環境の出力
Found a row: id = 57590, fn = 0
$VAR1 = {
'page' => '0',
'id' => '57590'
};
新環境の出力
Found a row: id = 57590, fn = 0
$VAR1 = {
'page' => 0,
'id' => 57590
};
Perl的には 0
でも '0'
でもコンテキストでよしなにやってくれるので良いのですが、
$ perl -E "say '0' eq 0"
1
$ perl -E "say '0' == 0"
1
この値がJSON化(JSON::to_json
)されて別の箇所で利用されており、
悪いことに某所でjs側で以下のようなよろしくないロジックが入ってしまっておりました。。
if (mode === '0') {
mode = 1234;
}
JavaScriptだと文字列の '0'
と数値の 0
では ===
だと全然違う挙動になってしまうので、
非常に微妙なバグになってしまっていました。
幸いテスト期間で発見できたのでユーザ影響はなかったのですが、
の記事にもあるように、
を使って型を明示的にしたほうが良さそうですねぇ。。
本件ですが、当時DBIの実装なども少し見てみたのですが、具体的にどこのアップグレードの時点で発生したのかを追いきれませんでした。
DBI::st->bind_col
のXSモジュール側あたりの問題でしょうか…?
有識者の方がいらっしゃいましたらご教示いただけると助かります。。
この現象が一番恐ろしかったやつとして思い出したので、ここにメモとして残しておきます。
8年ぶりにバージョンを上げようとするとこういう痛い事になったりするので、
何事も溜め込まない方が良いですねぇ、という感じでした。
【2024-01-14 11:35追記】
本件、有識者から教えていただきました!
どうやら、
の DBD::mysql
の4.038でこの変更が入っていたようです。
Perl's IV in scalar can store 64bit integer when perl was compiled with
64bit support (default on 64bit linux with gcc). Use this feature and
stores MYSQL_TYPE_LONGLONG as integers instead strings when possible.
確かにMySQL 8.0対応に伴って DBD::mysql
は 4.033
-> 4.050
に上げていたのでした。。
原因がわかってスッキリしました。 アナグラさん、ありがとうございました!
以上になります。
もし他にも思い出したら追記などできればと思います。