2017-04-20 15 views
0

私の理解はOUTです。仮パラメータは、プロシージャが呼び出されると常にNULLにデフォルト設定する必要があります。OracleのoutパラメータがNULLでない場合

create or replace package parameter_tests as 
    procedure callerproc; 
end parameter_tests; 
/
create or replace package body parameter_tests as 

procedure getstring(p_str out varchar) is 
begin 
    if p_str is null then 
    dbms_output.put_line('parameter null'); 
    else 
    dbms_output.put_line('parameter NOT null'); 
    end if; 
    p_str :='zz'; 
end getstring; 


procedure getcursor(p_out out sys_refcursor) is 
begin 
    if p_out%isopen then 
     dbms_output.put_line('cursor open'); 
    else 
     dbms_output.put_line('cursor closed'); 
    end if; 

    open p_out for 
    select * 
    from dual; 
end getcursor; 

procedure callerproc is 
    lv_cursor sys_refcursor; 
    lv_string varchar2(2) := null; 
begin 
    for i in 1..2 loop 
    getstring(lv_string); 

    getcursor(lv_cursor); 
    end loop; 

end callerproc; 
end parameter_tests; 
/

set serveroutput on 
begin 
    parameter_tests.CALLERPROC; 
end; 
/

parameter_tests.getstringは、callerprocループの周りに「パラメータnull」を両方とも出力すると予想します。そして、コードを実行すると、まさにそれが起こります。

しかし、parameter_tests.getcursorの出力は、参照カーソルがループの周りで2度目に開いていることを示します。

getcursorが呼び出されたときに仮パラメータp_outがNULLになっていれば、参照カーソルを閉じることができます。その代わりに、開いている参照カーソルを渡します。実際には、開いている参照カーソルを整理するOPEN FOR(何百回も繰り返すと最大オープンカーソルに当たらないようにします)です。

私は手動で呼び出し間の参照カーソルをnullにすると、期待どおりの動作をします。

OUTパラメータの場合、参照カーソルが特別なケースとして扱われる理由は誰にでも分かりますか?また、他のどのような種類の処理が異なっていますか?

データベースのバージョンは11.2.0.2.0です。

答えて

1

According to the documentation

サブプログラムの仮パラメータとしてカーソル変数を宣言:

  • サブプログラムがカーソル変数に値を開いたり割り当てる場合、パラメータ・モードでなければなりませんIN OUT。
  • サブプログラムがカーソル変数からのみフェッチまたはクローズする場合、パラメータ・モードはINまたはIN OUTのいずれかになります。

カーソルのパラメータは、あなただけ実際OUTとしてそれを宣言していても、それがOUTのように宣言されたかのように扱われているようです。この振る舞いは、IN OUTから見えるものです。 2番目の呼び出しでカーソルを取得して、2つの値からダミー値を確認することもできます。

REFカーソルの性質をポインタとすると意味がありますが、OUTのみが指定されていればコンパイラのエラーが発生すると考えられます(警告としても報告されません) 。偶然にも、ドキュメントの例はOUTだけでうまく動作します。

本当にこれは、間違ったパラメータの方向を報告しないので、コンパイラのバグのように見えます。 IN OUTとして宣言されていないため、コード内のバグ(もっと浅い!)もあります。

procedure callerproc is 
    lv_cursor sys_refcursor; 
    lv_string varchar2(20) := null; 
begin 
    for i in 1..2 loop 
    getstring(lv_string); 

    getcursor(lv_cursor); 

    close lv_cursor; 
    end loop; 

end callerproc; 

カーソル変数にnullを代入するよりもおそらくより正確である:あまりにも問題が「修正」に表示されない、一種の - そして、おそらく、さらにバグが明示的にカーソルをクローズしていないので、あなたが言及しているのは、また動作します。

+0

偉大な答え。ありがとうございました。あなたは明白な閉鎖が最良の選択であることについて正しいです。問題の原因は、実際にはクローズされていないカーソルの問題を調査しており、カーソルをループで開くことでカーソルの制限を超えることができないことがわかった。 –

関連する問題