4

function_publicOracle パッケージと、その中の 2 つの関数 (公開関数 ( ) と非公開関数 ( ))を作成したいと考えていますfunction_private。パブリック関数は、SQL ステートメントでプライベート関数を使用します。

プラグマがないと、コードはコンパイルされません ( 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公開も行います。パッケージ本体にしかない関数にプラグマを追加する解決策はありますか?

更新:疑似コードを実際の (簡略化された) 例に置き換えました。

UPDATE2 : Rob van Wijk によって提案されたコードのバグ修正。

4

4 に答える 4

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;
于 2010-05-10T13:23:57.317 に答える
2

Yourfunction_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 プラグマのポイントは、パッケージ仕様で宣言されたプロシージャが、パッケージ本体のソースにアクセスできない可能性がある他のユーザー (スキーマ) によって所有または実行される SQL ステートメントであっても、他のパッケージで使用できることです。プラグマは、私たちのコードを彼らのコードに組み込むことの影響について、彼らに保証を提供する方法です。そのため、プラグマを仕様で宣言する必要があります。これは、パッケージの EXECUTE を別のユーザーに許可するときに公開されるコードの唯一の部分であるためです。

編集

ああ、改訂されたコード例を見て、あなたが何をしようとしているのか理解できました。機能しない、機能しない、機能しない。spec = public functions - 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 は、スコープ ルールに関して完全に一致しているわけではありません。パッケージ化された SQL ステートメントでプライベート変数を使用できます。

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 が仕様で宣言しなければならないのは関数と型だけです。

于 2010-05-10T10:39:06.273 に答える
1

「WNDS、WNPSプラグマを追加したい...」と書いています。なぜあなたはそれが好きですか?バージョン 9 以降 (私が思うに)、Oracle がこのチェックを行います。プラグマを自分で追加する唯一の理由は、次の場合です。

  • SQL ステートメント内で関数 AND を使用する場所がわかっている

  • この用途に必要な純度レベルを知っている、かつ

  • 実行時ではなくコンパイル時に違反を見つけたい

最も簡単なオプションは、すべてのプラグマ宣言を完全にスキップすることです。

そうは言っても、TRUST キーワードを function_public の restrict_references プラグマに追加すると、restrict_references プラグマを function_private に省略できます。

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

よろしく、ロブ。

于 2010-05-10T09:06:14.277 に答える
0

Oracle がこのチェックを行います。

function_public次のコードは、 pragmaがあり、テーブルを読み取るRNDS呼び出しを行うため、コンパイルされません。function_private

PLS-00452: サブプログラム'FUNCTION_PUBLIC'は関連するプラグマに違反しています

SELECTからを削除するfunction_privateと、機能します。


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;
于 2010-05-10T08:37:40.740 に答える