2010-05-10 33 views
4

我想創建一個Oracle包和兩個函數:公共函數(function_public)和私有函數(function_private)。公共函數在sql語句中使用私有函數。在Oracle包體中使用Pragma

沒有編譯的代碼不能編譯(PLS-00231: function 'FUNCTION_PRIVATE' may not be used in SQL

CREATE OR REPLACE PACKAGE PRAGMA_TEST AS 
    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2; 
END PRAGMA_TEST; 

CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS 
    FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS 
    BEGIN 
    return 'z'; 
    END; 

    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS 
    ret VARCHAR2(100); 
    BEGIN 
    SELECT 'x' || function_private(x) INTO ret FROM dual; 
    return ret; 
    END; 
END PRAGMA_TEST; 

代碼編譯如果我添加WNDS, WNPS編譯到function_private。在我看來,編譯只能在包聲明中使用,而不是在包身上,所以我必須在包裝申報function_private還有:

CREATE OR REPLACE PACKAGE PRAGMA_TEST AS 
    FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2; 
    PRAGMA RESTRICT_REFERENCES(function_private, WNDS, WNPS); 
    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2; 
END PRAGMA_TEST; 

CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS 
    FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS 
    BEGIN 
    return 'z'; 
    END; 

    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS 
    ret VARCHAR2(100); 
    BEGIN 
    SELECT 'x' || function_private(x) INTO ret FROM dual; 
    return ret; 
    END; 
END PRAGMA_TEST; 

該解決方案使我function_private公衆以及。有沒有解決方案可以將編譯指示添加到只能在包體中找到的函數?

UPDATE:代替僞代碼與工作(簡化的)例子。

UPDATE2:由Rob van Wijk建議的代碼中的錯誤修正。

+2

您的示例不起作用。變量ret沒有聲明,你的函數沒有返回語句。而且:這似乎不是一個關於雜注的問題。您的函數無法編譯,因爲您嘗試在SQL中調用function_private。私有函數永遠不能從SQL中調用,所以它無論如何都需要公開。 – 2010-05-10 12:00:47

回答

8

您的問題與PRAGMA無關。正如Rob所說,現代化的Oracle版本可以自動處理大部分內容。

問題是你不能從SQL語句中調用私有函數,甚至嵌入在同一個包中的另一個子程序中。當PL/SQL執行SQL時,它將被移交給SQL引擎執行,並且基本上使您不在包的範圍之內,因此它無法訪問私有成員。

編譯沒有 - 沒有編譯指示,但使得「私人」功能市民:

CREATE OR REPLACE PACKAGE PRAGMA_TEST AS 
    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2; 
    FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2; 
END PRAGMA_TEST; 


CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS 
    FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS 
    BEGIN 
    return 'z'; 
    END; 

    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS 
    ret VARCHAR2(30); 
    BEGIN 
    SELECT 'x' || function_private(x) INTO ret FROM dual; 
    RETURN ret; 
    END; 
END PRAGMA_TEST; 

如果你想保持私人的功能,你需要看,如果你能在這樣的重寫公共職能調用私有函數的方法是在SQL語句之外完成的:

CREATE OR REPLACE PACKAGE PRAGMA_TEST AS 
    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2; 
END PRAGMA_TEST; 


CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS 
    FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS 
    BEGIN 
    return 'z'; 
    END; 

    FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS 
    ret VARCHAR2(30); 
    BEGIN 
    ret := function_private(x); 
    SELECT 'x' || ret INTO ret FROM dual; 
    RETURN ret; 
    END; 
END PRAGMA_TEST; 
0

Oracle執行此檢查。

以下代碼無法編譯,因爲function_public的編譯指示爲RNDS,它調用function_private讀取表。

PLS-00452:子程序 'FUNCTION_PUBLIC' 違反了與其相關的編譯

取下function_privateSELECT和它的作品。


CREATE OR REPLACE PACKAGE pragma_test AS 
    FUNCTION function_public RETURN VARCHAR2; 
    PRAGMA RESTRICT_REFERENCES(function_public, RNDS); 
END pragma_test; 

CREATE OR REPLACE PACKAGE BODY pragma_test AS 
    FUNCTION function_private RETURN VARCHAR2 IS 
    v_return dual.dummy%TYPE; 
    BEGIN 
    SELECT dummy INTO v_return FROM dual; 
    RETURN v_return; 
    END; 
    -- 
    FUNCTION function_public RETURN VARCHAR2 IS 
    v_return dual.dummy%TYPE; 
    BEGIN 
    RETURN function_private; 
    END; 
END pragma_test; 
+0

在你的例子中,function_private違反了編譯指示,所以Oracle給出錯誤是很好的。在我的示例中,function_private不違反WNDS WNPS編譯指示。我的第二個例子編譯得很好,我的問題是package中的function_private的顯式使用。 – asalamon74 2010-05-10 09:41:41

1

你寫 「我想補充WNDS,WNPS編譯...」。你爲什麼喜歡這個?自從版本9(我認爲)Oracle會爲您檢查。你可能要自己添加附註的唯一原因,是當:

  • 你知道在SQL語句中要使用你知道的功能和

  • 這是需要這種純度水平使用AND

  • 要找出違規在編譯的時候,而不是運行時間

最簡單的方法是隻跳過所有雜注聲明。

說了這麼多,如果將TRUST關鍵字添加到function_public的restrict_references pragma中,可以省略restrict_references pragma到function_private。

http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96590/adg10pck.htm#21958

問候, 羅布。

+0

我已經更新了這個問題,用一個更好的例子替換了僞代碼。 – asalamon74 2010-05-10 10:06:45

+0

TRUST關鍵字解決了我的其他問題之一,謝謝。 – asalamon74 2010-05-11 07:03:05

2

您的function_private僅在包體中聲明,因此其範圍僅限於包中的其他過程。因此它必須符合那些調用過程的純度級別,否則編譯器會拋出異常。

這個比較安全的聲明(注意,我已經擴展了function_public的純度)...

SQL> CREATE OR REPLACE PACKAGE PRAGMA_TEST AS 
    2 FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2; 
    3 PRAGMA RESTRICT_REFERENCES(function_public, WNDS, WNPS, RNDS); 
    4 END PRAGMA_TEST; 
    5/

Package created. 

SQL> CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS 
    2 FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS 
    3 BEGIN 
    4  return 'no harm done'; 
    5 END; 
    6 
    7 FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS 
    8 BEGIN 
    9  return function_private(x); 
10 END; 
11 END PRAGMA_TEST; 
12/

Package body created. 

SQL> 

...這個不安全的一個...

SQL> CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS 
    2 FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS 
    3  rv varchar2(1); 
    4 BEGIN 
    5  select dummy into rv from dual; 
    6  return rv; 
    7 END; 
    8 
    9 FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS 
10 BEGIN 
11  return function_private(x); 
12 END; 
13 END PRAGMA_TEST; 
14/

Warning: Package Body created with compilation errors. 

SQL> sho err 
Errors for PACKAGE BODY PRAGMA_TEST: 

LINE/COL ERROR 
-------- ----------------------------------------------------------------- 
9/3  PLS-00452: Subprogram 'FUNCTION_PUBLIC' violates its associated 
     pragma 

SQL> 

的點RESTRICTS_REFERENCES pragma是程序包規範中聲明的程序可以被其他程序包使用,甚至是由其他用戶(模式)擁有或執行的SQL語句,這些用戶可能無法訪問我們的程序包主體的源代碼。編譯指示是我們向他們保證將我們的代碼納入其中的影響的一種方法。這就是爲什麼必須在規範中聲明編譯指示的原因,因爲當我們將包上的EXECUTE授予其他用戶時,這是唯一暴露的代碼部分。

編輯

啊,現在已經看到了你修改後的代碼示例中,我明白你想要做什麼。它不,不會,不會工作。我們只允許使用在spec = public函數中聲明的打包函數 - 在SQL中。無論SQL是使用SQL * Plus編寫還是使用另一個打包過程進行編碼都無關緊要。之所以是錯誤堆棧中相當明確:

SQL> CREATE OR REPLACE PACKAGE PRAGMA_TEST AS 
    2  FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2; 
    3  PRAGMA RESTRICT_REFERENCES(function_public, WNDS, WNPS); 
    4 END PRAGMA_TEST; 
    5/

Package created. 

SQL> CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS 
    2 FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS 
    3  rv varchar2(1); 
    4 BEGIN 
    5  select dummy into rv from dual; 
    6  return rv; 
    7 END; 
    8 
    9 FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS 
10  rv varchar2(1); 
11 BEGIN 
12  select function_private(x) into rv from dual; 
13  return rv; 
14 END; 
15 END PRAGMA_TEST; 
16/

Warning: Package Body created with compilation errors. 

SQL> sho err 
Errors for PACKAGE BODY PRAGMA_TEST: 

LINE/COL ERROR 
-------- ----------------------------------------------------------------- 
12/6  PL/SQL: SQL Statement ignored 
12/13 PL/SQL: ORA-00904: : invalid identifier 
12/13 PLS-00231: function 'FUNCTION_PRIVATE' may not be used in SQL 
SQL> 

編譯器擲出ORA-00904: invalid identifier因爲功能不規範申報;它無關,與純度水平,

有關範圍的說明

PL/SQL並不完全是由與問候its scoping rules

SQL> CREATE OR REPLACE PACKAGE BODY PRAGMA_TEST AS 
    2 
    3 gv constant varchar2(8) := 'global'; 
    4 
    5 FUNCTION function_private(y IN VARCHAR2) RETURN VARCHAR2 IS 
    6  rv varchar2(1); 
    7 BEGIN 
    8  select dummy into rv from dual; 
    9  return rv; 
10 END; 
11 
12 FUNCTION function_public(x IN VARCHAR2) RETURN VARCHAR2 IS 
13  rv varchar2(10); 
14 BEGIN 
15  select gv||'+'||dummy into rv from dual; 
16  return rv; 
17 END; 
18 END PRAGMA_TEST; 
19/

Package body created. 

SQL> 
:我們可以在包裝SQL語句中使用私有變量

這只是函數和類型,wm必須在規範中聲明,如果我們想在SQL語句中使用它們。