わかった! $rs->search() をつなげて検索をかけていたのだが、これで最初のsearch()だけでpageとrowsを指定していたにもかかわらず、searchの実装として以下のようになっているため、offsetがどんどん増えて行ってしまう:
my $rs = DBIx::Class::Resultset->new(..., { page => $p, rows => $r });
# この時点で、$rs->{attrs}{page}, $rs->{attrs}{rows}を元に$rs->{attrs}{offset}
# が$p と $rを元にして計算される
# 条件1で検索
$rs = $rs->search( ... ); # ここでD::C::ResultSet->new がまた呼ばれる
# 条件2で検索
$rs = $rs->search( ... ); # さらにもう一回newが呼ばれる
ポイントはそれぞれのsearchの呼び出しの時にnewが呼ばれて、offsetが更新される事。つまり
offset += row * (page - 1);
として毎回計算されるわけだ。でもrowとpageは毎回同じものがコンストラクタに渡されるから、searchの度にoffsetが足される。そりゃあページングもずれます。
というわけで、教訓:ページングは一番最後に指定!
my $rs = $schema->resultset('Hoge');
$rs = $rs->search( \%where1 );
$rs = $rs->search( \%where2 );
$rs = $rs->search( \%where3 );
# で、最後に
$rs = $rs->search( undef, { rows => $rows, page => $page });
コメント