Oracle out参数未被NULL

时间:2017-04-20 16:42:23

标签: oracle plsql

我的理解是在调用过程时,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循环周围两次输出“Parameter null”。当你运行的代码恰好发生了什么。

然而,parameter_tests.getcursor的输出表明参考光标仍然在循环周围第二次打开。

如果在调用getcursor时正式参数p_out被置零,我们希望它关闭引用游标。相反,它传递打开的参考光标,它实际上是打开参考光标的OPEN FOR(如果循环数百次,则阻止我们点击最大打开光标)。

如果我在调用之间手动取消引用游标,它的行为就像我们期望的那样。

任何人都可以告诉我为什么参考游标在OUT参数时作为特殊情况处理?还有哪些其他类型的处理方式不同?

数据库版本为11.2.0.2.0。

1 个答案:

答案 0 :(得分:1)

According to the documentation

  

将游标变量声明为子程序的形式参数时:

     
      
  • 如果子程序打开或为游标变量赋值,则参数模式必须为IN OUT。
  •   
  • 如果子程序仅从光标变量中取出或关闭,则参数模式可以是IN或IN OUT。
  •   

将游标参数视为已声明为IN OUT,即使您实际上只将其声明为OUT。这种行为是你期望从IN OUT看到的;您甚至可以在第二次调用中获取光标,并查看双重虚拟值。

考虑到引用游标作为指针的性质,这是有道理的,但是如果只指定了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更正确,你提到它也可以。