PL/SQLオブジェクトのACCESSIBLE BY句を試す（Oracle Database 12c Release 2)

  Oracle Database 12c のPL/SQLを使うオブジェクト（PROCEDURE, FUNCTION, PACKAGE, PACKAGE BODY)の定義時には、ACCESSIBLE BY句を使って実行可能な上位のオブジェクトを指定することができるようになりました。
  これまではオブジェクトの実行権限はユーザーやロールに対してGRANT文で許可を与えていました。ACCESSIBLE BY句の機能を使うと、ユーザーやロールに加えてオブジェクト名まで指定して許可を制限できるようになります。例えば、作成したファンクションfunc1の実行をparent1プロシージャからのみ許可するといったことを制限できるようになります。

# 構文
ACCESSIBLE BY句はCREATE FUNCTION文やCREATE PACKAGE文のPL/SQLブロックの前に指定します。
構文の詳細は「 [PL/SQL言語リファレンス] (https://docs.oracle.com/cd/E82638_01/LNPLS/ACCESSIBLE-BY-clause.htm#GUID-9720619C-9862-4123-96E7-3E85F240FF36) 」を参照してください。

`ACCESSIBLE BY (種類 [スキーマ名.]オブジェクト名 [, 種類 [スキーマ名.]オブジェクト名] [, ...])`

**種類**には、アクセスを許可するオブジェクトの種類（FUNCTION / PROCEDURE / PACKAGE / TRIGGER / TYPE）を指定します。
**オブジェクト名**にはアクセスを許可するOracle Databaseオブジェクト名を指定します。スキーマ名を指定しない場合、自スキーマ内のオブジェクトとみなされます。
複数指定する場合にはカンマ（,）で区切って指定します。

# 単純な例
 以下のようなパッケージを作成します。CREATE PACKAGE文にACCESSIBLE BY (FUNCTION func1) を指定しています。これは同じユーザー（スキーマ）のfunc1以外からはこのパッケージを実行できないことを示しています。

```SQL
CREATE OR REPLACE PACKAGE pkg_name1
ACCESSIBLE BY (FUNCTION func1)
AS

PROCEDURE pkg1_proc1(param1 IN VARCHAR2);

END;
/
```

上記パッケージのプロシージャを実行するファンクションを作成します。許可されているファンクションfunc1から実行しているため、CREATE FUNCTION文は成功します。

```SQL
SQL> CREATE OR REPLACE FUNCTION func1(param1 IN VARCHAR2)
RETURN VARCHAR2 IS
BEGIN
    pkg_name1.pkg1_proc1(param1);
    RETURN 'func1 param: ' || param1;
END;
/

ファンクションが作成されました。

```

一方で、同じパッケージをファンクションfunc2から実行してみます。
許可されていないファンクション名であるため、CREATE FUNCTION文は失敗します。

```SQL
SQL> CREATE OR REPLACE FUNCTION func2(param1 IN VARCHAR2)
     RETURN VARCHAR2 IS
     BEGIN
         pkg_name1.pkg1_proc1(param1);
         RETURN 'func2 param: ' || param1;
     END;
    /

警告: ファンクションが作成されましたが、コンパイル・エラーがあります。

SQL> SHOW ERROR
FUNCTION FUNC2のエラーです。

LINE/COL ERROR
-------- -----------------------------------------------------------------
4/5      PL/SQL: Statement ignored
4/5      PLS-00904:
         オブジェクト'PKG_NAME1'にアクセスするには権限が不十分です。

SQL>
```

このようにACCESSIBLE BY句を指定すると、コールする側のオブジェクト作成時に実行許可がチェックされます。

# PACKAGE内のPROCEDUREのみ宣言

PACKAGE宣言部に指定せず、パッケージ内のPROCEDUREにACCESSIBLE句を指定してみます。
パッケージ内の個別のPROCEDURE / FUNCTIONにACCESSIBLE句を指定した場合、PACKAGE BODY内のPROCEDURE / FUNCTIONの宣言部に同じACCESSIBLE句を指定する必要があります。設定しないとエラー「PLS-00263: サブプログラム仕様部と本体のACCESSIBLE BYが一致していません」が発生します。

```SQL
CREATE OR REPLACE PACKAGE pkg_name1
AS

PROCEDURE pkg1_proc2(param1 IN VARCHAR2) ACCESSIBLE BY (FUNCTION func2);

END;
/
```

パッケージpkg_name1内のプロシージャpkg1_proc2を実行するファンクションfunc1を作成してみます。やはり権限が無いというエラーになります。

```SQL
SQL> CREATE OR REPLACE FUNCTION func1(param1 IN VARCHAR2)
  2  RETURN VARCHAR2 IS
  3  BEGIN
  4      pkg_name1.pkg1_proc2(param1);
  5      RETURN 'func1 param: ' || param1;
  6  END;
  7  /

警告: ファンクションが作成されましたが、コンパイル・エラーがあります。

SQL>
SQL> SHOW ERROR
FUNCTION FUNC1のエラーです。

LINE/COL ERROR
-------- -----------------------------------------------------------------
4/5      PLS-00904:
         オブジェクト'PKG1_PROC2'にアクセスするには権限が不十分です。

```

# PACKAGE宣言とPROCEDURE宣言両方に宣言(1)
PACKAGE内の特定のPROCEDUREに異なるACCESSIBLE句を指定してみます。
下記の例ではCREATE PACKAGE部分では、FUNCTION func1を、PROCEDURE pkg1_proc3にはFUNCTION func2を指定しています。

```SQL
SQL> CREATE OR REPLACE PACKAGE pkg_name1
ACCESSIBLE BY (FUNCTION func1)
AS

PROCEDURE pkg1_proc3(param1 IN VARCHAR2) ACCESSIBLE BY (FUNCTION func2);

END;
/

パッケージが作成されました。

```

この状態で、パッケージを実行するFUNCTIONを作成してみます。

```SQL
SQL> CREATE OR REPLACE FUNCTION func2(param1 IN VARCHAR2)
  2  RETURN VARCHAR2 IS
  3  BEGIN
  4      pkg_name1.pkg1_proc3(param1);
  5      RETURN 'func2 param: ' || param1;
  6  END;
  7  /

警告: ファンクションが作成されましたが、コンパイル・エラーがあります。

SQL> SHOW ERROR
FUNCTION FUNC2のエラーです。

LINE/COL ERROR
-------- -----------------------------------------------------------------
4/5      PL/SQL: Statement ignored
4/5      PLS-00904:
         オブジェクト'PKG_NAME1'にアクセスするには権限が不十分です。

SQL>
```

PACKAGE部分のアクセス制限ではじかれているようです。このため、PACKAGE宣言部とパッケージ内のプロシージャでACCESSIBLE BY句を両方指定する場合はPACKAGE部分にアクセス権限が必要だということがわかります。

# PACKAGE宣言とPROCEDURE宣言両方に宣言(2)
次にPACKAGE内の特定のPROCEDUREに異なるACCESSIBLE句を指定するが、PROCEDURE部分の方を制限してみます。
下記の例ではCREATE PACKAGE部分では、FUNCTION func1, func2を、PROCEDURE pkg1_proc2にはFUNCTION func1を指定しています。

```SQL
CREATE OR REPLACE PACKAGE pkg_name1
ACCESSIBLE BY (FUNCTION func1, FUNCTION func2)
AS

PROCEDURE pkg1_proc4(param1 IN VARCHAR2) ACCESSIBLE BY (FUNCTION func1);

END;
/
```
この状態で、パッケージを実行するFUNCTIONを作成してみます。

```SQL
QL> CREATE OR REPLACE FUNCTION func2(param1 IN VARCHAR2)
  2  RETURN VARCHAR2 IS
  3  BEGIN
  4      pkg_name1.pkg1_proc4(param1);
  5      RETURN 'func2 param: ' || param1;
  6  END;
  7  /

警告: ファンクションが作成されましたが、コンパイル・エラーがあります。

SQL> SHOW ERROR
FUNCTION FUNC2のエラーです。

LINE/COL ERROR
-------- -----------------------------------------------------------------
4/5      PLS-00904:
         オブジェクト'PKG1_PROC4'にアクセスするには権限が不十分です。

SQL>
```
PACKAGE宣言でファンクションfunc2を許可していますが、PROCEDURE部分で許可していないため、権限が無いというエラーになります。

パッケージに対してACCESSIBLE BY句を指定する場合には、パッケージに対する許可とパッケージ内のファンクションやプロシージャ両方の許可が必要であることがわかります。