[pgsql-jp: 25802] Re: PL/pgSQL 文での関数について

Jun Kitamura kitamura @ zoozee.jp
2002年 5月 5日 (日) 01:13:58 JST


北村@zoozee です。

> PL/pgSQL文でストアドプロシージャーを作成中なのですが、
> select intoではFOUNDにてエラー検知しアボートできますが、
> insertやupdateを実行したときのエラー処理(エラーの検知)はできるのでしょうか
>> 出来るのでしたらそのやり方を、どなたかご教授下さい。

出来ません。(あっさり)

INSERT や UPDATE を行なった時のエラーが(重複エラーや NOT NULL などの制約
エラーなのだと思いますが)発生する時は、その(エラー元となる)データのために
整合性が既にとれていないわけです。そのため、強制的にトランザクションがロー
ルバックされ、アボートされます。

もし、既存なら○○とか、重複しているなら××、という処理をしたいなら、
INSERTや UPDATEの前には、本来制約チェックで自動的にエラーになるそれらを自
分で調べる必要があります。調べついでにロックをかける事になるのだと・・・。
そのための FOUND だと思います。

例:
create table t1(
 a int4, primary key(a),
 b int4 not null
);

-- a をキーにして、b に NULL を入れようとすると 0 が、
-- 追加したら 1、更新したら 2 が返る関数です。

create function f1(int4,int4) returns int2 as
'
 DECLARE
  val_a ALIAS FOR $1;
  val_b ALIAS FOR $2;
  retval int2;
  poi_a int4;
 BEGIN
  -- b の NOT NULL チェック
  IF val_b IS NULL THEN
   retval := 0;
  ELSE
   -- 既存?ついでにロック
   select val_a into poi_a from t1 where a = val_a FOR UPDATE;
   IF NOT FOUND THEN
    -- 無ければ追加
    insert into t1 (a,b) values (val_a,val_b);
    retval := 1;
   ELSE
    -- あったら更新
    update t1 set b = val_b where a = val_a;
    retval := 2;
   END IF;
  END IF;
  return retval;
 END;
'
language 'plpgsql';

例が悪い(笑)ので何とも言えないのですが、「こんな感じ」って事で。
このままだと INSERT 時に重複エラーになる可能性ありますね。BEGIN の後でテー
ブルロックかけたほうが良いのかな?ほんと悪い例ですんません。
では。




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