Oracle输出参数不为空';D

Oracle输出参数不为空';D,oracle,plsql,Oracle,Plsql,我的理解是,调用过程时,形式参数应始终默认为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 d

我的理解是,调用过程时,形式参数应始终默认为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”。当你运行代码的时候,事情就是这样发生的

但是,参数_tests.getcursor的输出表明,在循环的第二次循环中,引用游标仍然处于打开状态

如果在调用getcursor时形式参数p_out为null,我们希望它关闭引用游标。相反,它传递打开的引用光标,而实际上,它是清理打开的引用光标的open FOR(如果您循环数百次,它可以防止我们碰到最大打开的光标)

如果我在调用之间手动将引用游标设为null,它的行为将与我们预期的一样

有人能告诉我为什么引用游标在超出参数时被作为特例处理吗?还有哪些其他类型的处理方式不同

数据库版本为11.2.0.2.0。

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

  • 如果子程序打开或为游标变量赋值,则参数模式必须为IN-OUT
  • 如果子程序仅从游标变量获取或关闭游标变量,则参数模式可以是IN或IN OUT
游标参数似乎被视为已声明为IN-OUT,即使您实际上只将其声明为OUT。这种行为是你从里到外所期望看到的;您甚至可以在第二次调用中获取游标,并查看dual中的伪值

考虑到ref游标作为指针的性质,这有点道理,但是如果只指定了OUT(甚至没有作为警告报告),您可能会认为编译器错误将强制执行该规则。顺便说一句,文档中的示例也适用于just OUT

这看起来像是一个编译器错误,因为它不会报告错误的参数方向;但是(更微妙的是!)代码中也有一个bug,因为它没有声明为in-OUT。而且,可能还有一个bug,因为您没有显式关闭光标-这似乎也“修复”了问题,有点:

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赋值给cursor变量更正确,您提到的同样有效。

回答得很好。非常感谢。关于明确关闭是最佳选择,您是对的。问题的根源实际上是调查一个未关闭游标的问题,我们发现我们不能通过循环打开它们来超过游标限制。