はじめに
2026年11月、PHPのZend Framework 1を継承するオープンソースプロジェクト「ZF1-Future」で、IBM Db2向けのページング処理を改善するPRが正式にマージされました。
今回の改修は、実は私が2023年11月に提出したPRがベースとなっています。
約3年の時を経て、プロジェクトのメンテナーさんによって改良が加えられ、ようやく正式に採用されました。
個人的にはとても嬉しい出来事なのですが、今回の変更では古いDb2との後方互換性が一部失われるため、IBM iを利用されている方に注意点を共有したいと思います。
Shardj/zf1-future - Improving limit method using LIMIT,OFFSET - #393
何が変わったのか?
今回変更されたのは、以下のDb2アダプターです。
Zend_Db_Adapter_Db2-
Zend_Db_Adapter_Pdo_Ibm
これらのアダプターに実装されているlimit()メソッドのSQL生成方法が変更されました。
従来の処理
これまでの実装では、ROW_NUMBER()を利用し、サブクエリを組み立てることでページング処理を実現していました。
概念的には以下のようなSQLです。
SELECT *
FROM (
SELECT T.*,
ROW_NUMBER() OVER (ORDER BY ID) AS ZEND_DB_ROWNUM
FROM MYLIB.MYTABLE T
) X
WHERE ZEND_DB_ROWNUM BETWEEN 101 AND 120
実際の旧実装では、元のSQLに応じて、さらに複雑な組み立てが行われていました。
今回の新しい処理
新しい実装では、Db2のOFFSETとFETCH FIRSTを利用する方式に変更されました。
SELECT *
FROM MYLIB.MYTABLE
ORDER BY ID
OFFSET 100 ROWS FETCH FIRST 20 ROWS ONLY
非常にシンプルになりました。
現在のDb2.phpでは、以下のように実装されています。
if ($offset === 0) {
return $sql . " FETCH FIRST $count ROWS ONLY";
}
return $sql . " OFFSET $offset ROWS FETCH FIRST $count ROWS ONLY";
この変更によって、従来必要だった複雑なサブクエリの生成が不要となりました。
また、以前の方式では結果セットに含まれていたZEND_DB_ROWNUM列が、今回の実装では追加されなくなりました。
注意!古いDb2では動かなくなる可能性
今回の変更で注意したいのは、OFFSET構文に対応していない古いDb2では、ページング処理が正常に動作しなくなることです。
メンテナーさんも変更履歴に、以下の対応要件を明記しています。
| データベース | 必要なバージョン |
|---|---|
| Db2 for i | IBM i 7.1 TR11以降 |
| Db2 for i | IBM i 7.2 TR3以降 |
| Db2 for i | IBM i 7.3以降 |
| Db2 LUW | 11.1以降 |
IBM i 7.1、7.2では、必要なPTFの適用状況にも注意してください。(※これらバージョンは正規のサポートは終了しているので、本質的にはOSのバージョンアップをすべきかと思いますが...)
どのような問題が起きるのか?
例えば、次のコードを実行する場合です。
$db->limit(
'SELECT * FROM MYLIB.MYTABLE ORDER BY ID',
20,
100
);
新しいアダプターでは、次のSQLが生成されます。
SELECT * FROM MYLIB.MYTABLE
ORDER BY ID
OFFSET 100 ROWS FETCH FIRST 20 ROWS ONLY
OFFSETに対応していないDb2では、このSQLが構文エラーとなります。
ただし、offsetが0の場合は次のSQLになります。
SELECT * FROM MYLIB.MYTABLE
ORDER BY ID
FETCH FIRST 20 ROWS ONLY
こちらは以前から存在する構文ですので、対応している古いDb2でも動作します。
つまり、1ページ目は正常に表示できるのに、2ページ目以降でエラーになる、といった現象が発生する可能性があります。
なお、今回の変更はlimit()メソッドに関するものです。通常のSELECT、INSERT、UPDATE、DELETEなどが、この改修だけを理由に利用できなくなるわけではありません。
古いIBM iを利用している場合は?
IBM i 7.1 TR10以前、または7.2 TR2以前の環境では、今回のOFFSET構文を利用できません。
これらの環境でZF1-Futureのlimit()を利用している場合は、新しい実装への更新に注意が必要です。
対処方法の一つとして、従来のROW_NUMBER()方式を使用しているZF1-Futureのバージョンを継続利用する方法があります。
2026年11月4日時点では、GitHub Releasesに掲載されている最新版はrelease-1.25.2で、今回のPRはmasterブランチに取り込まれた段階です。
ただし、旧バージョンを利用する場合でも、PHPとの互換性やセキュリティ修正の状況を確認してください。
特に、古いIBM iそのものがサポート終了となっている場合は、OSの更新も含めた対応を検討する必要があります。
今回のPRについて
今回マージされたPR #393は、私が2023年11月に提出したものです。当時、Db2 for i向けのページング処理について改善を提案しました。
互換性を重視した別のPR #392は2024年1月にマージされましたが、よりシンプルな実装を目指したPR #393は、その後も残っていました。
今回、メンテナーさんがDb2 for iとDb2 LUWの両方を考慮して実装を改善し、正式にマージしてくれました。
長い間この提案を残し、改良したうえで採用してくださったZF1-Futureのメンテナーさんの皆さんに感謝しています。
まとめ
今回の変更は、Db2向けページング処理をシンプルにする改善です。
一方で、古いDb2との後方互換性は一部失われています。
既にIBM i 7.3以降を利用している環境では、今回のSQL構文の対応について大きな心配はありませんが、古いIBM iを継続利用している場合は注意が必要です。
ZF1-Futureは、今も多くの方々によってメンテナンスが続けられています。
長年使われてきたZend Framework 1を、現在のPHPやDb2環境でも利用できるようにしてくれるコミュニティには、本当に感謝しています。