プログラムパッケージは、パッケージヘッダー(PACKAGE SPECIFICATION)とパッケージボディ(PACKAGE BODY)の2つの部分で構成されており、同時にプログラムパッケージの定義は、パッケージヘッダーの定義とパッケージボディの定義に分かれます。
適用対象
この内容はOceanBaseデータベースEnterprise Editionにのみ適用されます。OceanBaseデータベースCommunity EditionはMySQLモードのみを提供します。
パッケージヘッダー(PACKAGE SPECIFICATION)部分では、パッケージ内のデータ型、変数、定数、カーソル、サブルーチン、例外処理などの要素を宣言します。これらの要素はパッケージの共有要素です。一方、パッケージボディ(PACKAGE BODY)はパッケージヘッダー部分の具体的な実装であり、パッケージヘッダー部分で宣言されたカーソルやプログラムを定義しています。また、パッケージボディ内ではパッケージのプライベート要素も宣言できます。
パッケージヘッダーとパッケージボディは別々にコンパイルされ、2つの独立したオブジェクトとしてデータベースの辞書ビューUSER_SOURCE、ALL_SOURCE、DBA_SOURCEに格納されます。
パッケージの作成
パッケージヘッダを作成する構文は以下のとおりです:
CREATE [OR REPLACE] PACKAGE package_name
[AUTHID {CURRENT_USER | DEFINER}]
{IS | AS}
[public_type_declarations[public_type_declarations]...]
[public_cursor_declarations[public_cursor_declarations]...]
[public_variable_declarations[public_variable_declarations]...]
[function_declarations[function_declarations]...]
[procedure_specifications[procedure_specifications]...]
END [package_name]
ここで、AUTHID CURRENT_USER と AUTHID DEFINER オプションは、アプリケーションが関数を呼び出す際に使用する権限モードを示します。
パッケージ本体の定義を作成する構文は以下のとおりです:
CREATE [OR REPLACE] PACKAGE BODY package_name
{AS|IS}
[private_type_declarations[private_type_declarations]...]
[private_variable_declarations[private_variable_declarations]...]
[private_function_declarations[function_declarations]...]
[private_procedure_specifications[procedure_specifications]...]
[public_cursor_declarations[public_cursor_declarations]...]
[public_function_declarations[function_declarations]...]
[public_procedure_specifications[procedure_specifications]...]
BEGIN
PL Statement
END [package_name]
例
以下の例では、プログラムパッケージの名前を obdemo_pack とし、このパッケージには変数 obDeptRec、関数が2つ、ストアドプロシージャが1つ含まれています。
obclient> CREATE TABLE obdept(
deptno NUMBER(10,0),
dname VARCHAR(15),
loc VARCHAR(20)
);
Query OK, 0 rows affected
obclient> CREATE OR REPLACE PACKAGE obdemo_pack
IS
obDeptRec obdept %ROWTYPE;
FUNCTION add_obdept(dept_no NUMBER, dept_name VARCHAR2, location VARCHAR2)
RETURN NUMBER;
FUNCTION remove_obdept(dept_no NUMBER)
RETURN NUMBER;
PROCEDURE query_obdept(dept_no IN NUMBER);
END obdemo_pack;
/
Query OK, 0 rows affected
以下の例では、パッケージ本体の作成メソッドが宣言されたパッケージヘッダーを実装しています:
obclient> CREATE OR REPLACE PACKAGE BODY obdemo_pack
IS
FUNCTION add_obdept(dept_no NUMBER, dept_name VARCHAR2, location VARCHAR2)
RETURN NUMBER
IS
deptno_remaining EXCEPTION;
PRAGMA EXCEPTION_INIT(deptno_remaining, -1); -- -1は一意性制約違反のエラーコードです
BEGIN
INSERT INTO obdept VALUES(dept_no, dept_name, location);
IF SQL%FOUND THEN
RETURN 1;
END IF;
EXCEPTION
WHEN deptno_remaining THEN
RETURN 0;
WHEN OTHERS THEN
RETURN -1;
END add_obdept;
FUNCTION remove_obdept(dept_no NUMBER)
RETURN NUMBER
IS
BEGIN
DELETE FROM obdept WHERE deptno=dept_no;
IF SQL%FOUND THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
EXCEPTION
WHEN OTHERS THEN
RETURN -1;
END remove_obdept;
PROCEDURE query_obdept (dept_no IN NUMBER)
IS
BEGIN
SELECT * INTO obDeptRec FROM obdept WHERE deptno=dept_no;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('データベースには、部門コードが'||dept_no||'の部門が存在しません');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('プログラム実行エラー!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'----'||SQLERRM);
END query_obdept;
BEGIN
Null;
END obdemo_pack;
/
Query OK, 0 rows affected
OceanBaseデータベースでは、プログラムパッケージでシノニムを作成することもサポートされており、その例は以下のとおりです:
obclient> CREATE OR REPLACE SYNONYM syn_pag FOR obdemo_pack;
Query OK, 0 rows affected
obclient> CALL syn_pag.query_obdept('123');
Query OK, 0 rows affected
プログラムパッケージの関数とメソッドの呼び出し
プログラムパッケージ内の変数、定数、関数、メソッドなどを呼び出すには、オブジェクト名にパッケージ名を含め、「.」で区切る必要があります。つまり、プログラムパッケージ内の共通要素を呼び出す形式は次のとおりです:パッケージ名.要素名。
以下の例では、obdemo_pack プログラムパッケージ内の関数を呼び出して obdept テーブルに対する挿入、クエリ、更新操作を実行し、obdemo_pack プログラムパッケージ内のレコード変数 obDeptRec を使用して照会したデータベース情報を表示します。
obclient> DECLARE
Var NUMBER;
BEGIN
Var := obdemo_pack.add_obdept(900,'Administration', 'Beijing');
IF var =-1 THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'----'||SQLERRM);
ELSIF var =0 THEN
DBMS_OUTPUT.PUT_LINE('該当部門のレコードは既に存在します!');
ELSE
DBMS_OUTPUT.PUT_LINE('レコードの追加に成功しました!');
obdemo_pack.query_obdept(900);
DBMS_OUTPUT.PUT_LINE(obdemo_pack.obDeptRec.deptno||'---'||obdemo_pack.obDeptRec.dname||'---'||obdemo_pack.obDeptRec.loc);
var := obdemo_pack.remove_obdept(900);
IF var =-1 THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'----'||SQLERRM);
ELSIF var=0 THEN
DBMS_OUTPUT.PUT_LINE('該当部門のレコードは存在しません!");
ELSE
DBMS_OUTPUT.PUT_LINE('レコードの削除に成功しました!');
END IF;
END IF;
END;
/
Query OK, 0 rows affected
レコードの追加に成功しました!
900---Administration---Beijing
レコードの削除に成功しました!