2017-02-03 20 views
1

«すでに使用中のカーソル»で失敗しますエラー:再帰PostgreSQLの機能は、私はこのようなバウンドパラメーター化カーソルを使用して再帰的なPL/pgSQL関数を持っているメッセージ

select test_cursor(true) 

Code: 42P03, ErrorMessage: cursor "cur" already in use 

明らかに、私のカーソルの範囲は単一の関数呼び出しに限定されません。この問題を回避するためにグーグル後、私は、結合していないカーソルがこの制限を持っていないことに言及メーリングリストのアーカイブにこのmessageを見つけすなわち:

declare 
    mycursor refcursor; 
begin 
    open mycursor for ...; 
end; 

しかし、私はアンバウンドカーソルをパラメータ化することができますどのように表示されません。また、私は結合していないカーソルでfor...loopを使用することはできません。

-- 42601: cursor FOR loop must use a bound cursor variable 
create or replace function test_cursor(rec boolean) returns void as $$ 
declare 
    cur refcursor; 
begin 
    open cur for select * from generate_series(1,3); 
    for c in cur loop 
     if rec then 
      perform test_cursor(false); 
     end if; 
    end loop; 
    close cur; 
end; 
$$ language plpgsql; 

は、誰かが別のアプローチを提案してもらえますか?

PS。私は、大量の再帰カーソルとパラメータ化されたカーソルを使用する大量のOracleストアドプロシージャを移植しています。グローバルにスコープされたカーソルでこの問題に遭遇するまで、変換は単純なようでした。

答えて

2

私はかなり奇妙に見える回避策を見つけましたが、まだ動作するようです。私はそれには何か欠点があるかどうかは分かりませんが、私の場合、唯一の選択肢は非常に多くのコードを手作業で書き直すことですので、試してみます。

ソリューションは、オープン・カーソルの範囲を制限するために、私は私の機能を再入力するたびに、私は新鮮なポータル名を取得するように、そのパブリック可視名(ポータル名)をランダム化することではありません。

create or replace function test_cursor(rec boolean default true) returns void as $$ 
declare 
    cur cursor(a int) for select * from generate_series(1,a); 
begin 
    -- assign a random string as a portal name 
    -- before iterating over the cursor 
    cur := random_portal_name(); 

    for c in cur(3) loop 
     if rec then 
      perform test_cursor(false); 
     end if; 
    end loop; 
end; 
$$ language plpgsql; 

ランダムな文字列を取得するには、シーケンスから次の値を取得する方法、UUIDを生成する方法などがあります。私は、その目的のために一時的な(セッションスコープの)シーケンスを作成するヘルパー関数を書いています:

create or replace function random_portal_name() returns varchar as $$ 
begin 
    create temp sequence if not exists portal_names; 
    return 'portal$' || nextval('portal_names'); 
end; 
$$ language plpgsql; 
関連する問題