プログラムパッケージは、パッケージヘッダー(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
レコードの削除に成功しました!