[pgsql-jp: 41049] Re: PL/pgSQL中のループ内での変数更新

花田 茂 hanada @ metrosystems.co.jp
2012年 2月 10日 (金) 19:40:19 JST


花田です。

(2012/02/10 18:03), xrstt070 @ yahoo.co.jp wrote:
> 先日投稿させてもらった内容について自分なりに調べてみましたが、
> 8.3.0の時点から変更されてるみたいです。
> 
> ちなみに該当するプログラムはpl_exec.cのexec_stmt_fori関数のようです。
> 
> ただし、この仕様が正しいのかはまだよくわかっておりませんが。。。
> リリースノートを見てみましたが、記載されていないのですかね?

おそらく、8.3 のリリースノートにある

・FORループのSTEP値の必要条件を厳密にしました。(Tom)
    非正のSTEP値を許しません。 また、ループのオーバーフローを取り扱いま
    す。

が該当する修正のようです。8.2.23 環境で提示していただいた test 関数の動
きをデバッガで追ったところ、ループ終端でのカウンタ減算で 0 から
18446744073709551615 にアンダーフローして、ループが一周で終了しました。

git のコミットでいうと 816ff27f60385d362898d8ac6523f043f888b1f5 です。

> commit 816ff27f60385d362898d8ac6523f043f888b1f5
> Author: Tom Lane <tgl @ sss.pgh.pa.us>
> Date:   Sun Jul 15 02:15:04 2007 +0000
> 
>     Reject zero or negative BY step in plpgsql integer FOR-loops, and behave
>     sanely if the loop value overflows int32 on the way to the end value.
>     Avoid useless computation of "SELECT 1" when BY is omitted.  Avoid some
>     type-punning between Datum and int4 that dates from the original coding.

この修正により、各周回の先頭でループカウンタが本来のカウンタ値にリセット
されるようになり、ループが回り始めてからカウンタを書き換えてループ回数を
制御する方法は使えなくなったようです。かなりわかりづらい挙動ですね。この
仕様ならば、いっそループカウンタは読み取り専用のほうがいい気もします。

なお、ループカウンタはループ開始時に自動的に定義されるので、DECLARE で定
義している iCnt は実際には使われていませんでした(コメントアウトしても同
じ挙動です)。

-- 
株式会社メトロシステムズ
  花田 茂
Mail : hanada @ metrosystems.co.jp
 Tel : 03-5951-1219
 Fax : 03-5951-2929


pgsql-jp メーリングリストの案内