2017-04-20 95 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循環的兩次輸出「Parameter null」。而當你運行的代碼正是發生了什麼。

但是,parameter_tests.getcursor的輸出表明參考光標仍然在循環中第二次打開。

如果調用getcursor時正式參數p_out被忽略,我們期望它關閉參考光標。相反,它傳遞的是開放的參考光標,實際上是OPEN FOR,用於打開參考光標(並且如果循環數百次,則阻止我們觸及最大打開的光標)。

如果我手動將參考光標置於調用之間,它的行爲就像我們預期的那樣。

任何人都可以告訴我,爲什麼引用遊標正在作爲特殊情況處理時,他們是OUT參數?還有哪些其他類型的處理方式不同?

數據庫版本是11.2.0.2.0。

回答

1

According to the documentation

當聲明遊標變量作爲子程序的形式參數:

  • 如果子程序打開或分配一個值,以將光標變量,那麼參數模式必須進出。
  • 如果子程序只從遊標變量中提取或關閉遊標變量,那麼參數模式可以是IN或IN OUT。

光標參數彷彿它已被聲明爲IN OUT被處理,即使你實際上只聲明爲OUT。這種行爲是你期望從IN OUT看到的;您甚至可以在第二次調用中獲取遊標,並查看來自dual的虛擬值。

考慮到ref cursor作爲指針的性質,這種排序是有道理的,但是如果只指定了OUT(並且它甚至不報告爲警告),您會認爲該規則將由編譯器錯誤執行。順便說一下,文檔中的示例也適用於OUT。

所以真的這看起來像一個編譯器的bug,因爲它沒有報告不正確的參數方向;但也(更簡單!)代碼中的錯誤,因爲它沒有被聲明爲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

很好的答案。謝謝。你明確的關閉是最好的選擇。問題的根源實際上是調查一個未關閉遊標的問題,我們發現我們不能通過在循環中打開它們來超出遊標限制。 –