1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ILERPGAdvent Calendar 2023

Day 21

ZendFramework1 future の Zend_Db_Adapter_Db2#limitメソッド

Last updated at Posted at 2023-12-20

ZendFramework1 futurePHP8.1 コンパチで動作する、ありがたいライブラリ。(※8.1 も 2024/11/25 で セキュリティサポート が来てしまいますが...)
過去の資産を使い、未だに多くの IBMi ユーザーが PHP 開発で、ZF1 を使用しており、PHPのバージョンアップでは、非常に助かっている。
しかし、旧ZF1時代から、Zend_Db_Adapter_Db2#limitメソッド に問題があり(※DB2 LUW 試していないのでわかりません)我々が IBMi で使用する際には、一工夫が必要。

参考リンク

問題の箇所

以下の箇所の OVER() だが、SQLに ORDER BY がない場合は正常に動作するが、ORDER BY が存在する場合は OVER(ORDER BY ...) にしなければならない部分が 抜け落ちている

  • OLAP の指定
    「OLAP-specification OVER( --- window-order-clause --- ) 」
/Zend/Db/Adapter/Db2.php
        /**
         * DB2 does not implement the LIMIT clause as some RDBMS do.
         * We have to simulate it with subqueries and ROWNUM.
         * Unfortunately because we use the column wildcard "*",
         * this puts an extra column into the query result set.
         */
        return "SELECT z2.*
            FROM (
                SELECT ROW_NUMBER() OVER() AS \"ZEND_DB_ROWNUM\", z1.*
                FROM (
                    " . $sql . "
                ) z1
            ) z2
            WHERE z2.zend_db_rownum BETWEEN " . ($offset+1) . " AND " . ($offset+$count);

上記問題を zf1-future の issue に上げた。 issue - Zend_Db_Adapter_Db2 limit does not work #391

対応

対応としては、OVER(ORDER BY ...) と、過去には存在しなかったが、今ではDB2でも実装されている LIMIT の何れかを使用する実装が考えられる。
OVER(ORDER BY ...) は、過去の DB2 バージョンのユーザーも使えるが、冗長で煩雑に見え、LIMIT の方は、他のDB製品とも近く、記述としてはシンプルになる。

/Zend/Db/Adapter/Db2.php 実装 OVER()
       // Add this piece and place $order in OVER() clause
        $pieces = preg_split("/order by/i", $sql);
        $order = "";
        if(array_key_exists(1, $pieces)) {
            $order = "ORDER BY " . $pieces[1];
        }

        $limit_sql = "SELECT z2.*
              FROM (
                 SELECT ROW_NUMBER() OVER($order) AS \"ZEND_DB_ROWNUM\", z1.*
                    FROM (
                       " . $sql . "
                    ) z1
               ) z2
               WHERE z2.zend_db_rownum BETWEEN " . ($offset+1) . " AND " . ($offset+$count);

        return $limit_sql;
    }

/Zend/Db/Adapter/Db2.php 実装 LIMIT
        $sql .= " LIMIT $count";
        if ($offset > 0) {
            $sql .= " OFFSET $offset";
        }

        return $sql;
    }

本体にいつ取り込まれるかは?未定なので、もし limitメソッド で困っている人は参考にまでどうぞ。

2024.01.26 追記

PR案 Shardj/zf1-future - Improving limit method using OVER() #392 に関しては、一旦マージして貰えました。これで少なくても IBM i で limit,OFFSET の改善にはなりました。Thanks!

こっち Shardj/zf1-future - Improving limit method using LIMIT,OFFSET #393 は現時点で discussion 中です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?