DBMS_DDLサブプログラムによるPL/SQLソース・テキストのラップ

DBMS_DDLパッケージには、WRAPファンクションおよびCREATE_WRAPPEDプロシージャが含まれていて、各ファンクションおよびプロシージャは、動的に生成された単一のラップ可能PL/SQLユニットのPL/SQLソース・テキストをラップします。また、DBMS_DDLパッケージには、WRAPまたはCREATE_WRAPPEDへの入力が有効なラップ可能PL/SQLユニットでない場合に発生する、例外MALFORMED_WRAP_INPUT(ORA-24230)も含まれます。(ラップ可能PL/SQLユニットのリストは、「PL/SQLのソース・テキストのラップ」の概要を参照してください。)

WRAPファンクションは、ラップ可能PL/SQLユニットを作成する単一のCREATE文を入力として取得し、PL/SQLソース・テキストがラップされた同等のCREATE文を戻します。WRAPファンクションの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

注意:

DBMS_DDL.WRAPによって戻される文を、データ型がVARCHAR2Aの仮パラメータstatementを含むDBMS_SQL.PARSEプロシージャに渡す場合、DBMS_SQL.PARSElfflgパラメータをFALSEに設定する必要があります。設定しないと、DBMS_SQL.PARSEによって、ラップされたPL/SQLユニットに行が追加され、ユニットが破損します。(DBMS_SQL.PARSEの構文は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。)

CREATE_WRAPPEDプロシージャは、その対応するWRAPファンクションと同じ処理を行って、戻されたCREATE文を実行し、指定されたPL/SQLユニットを作成します。CREATE_WRAPPEDプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

ヒント:

DBMS_DDLサブプログラムの起動時には、パッケージの完全修飾名SYS.DBMS_DDLを使用し、他のユーザーがDBMS_DDLという名前のローカル・パッケージを作成していたり、パブリック・シノニムDBMS_DDLを定義している場合に発生する名前の競合を回避します。

ノート:

WRAPファンクションまたはCREATE_WRAPPEDプロシージャに入力されるCREATE文は、そのサブプログラムを起動したユーザーの権限で実行されます。

例A-4では、EXECUTE IMMEDIATE文を使用してパッケージ仕様部を、およびCREATE_WRAPPEDプロシージャを使用してラップされたパッケージ本体を動的に作成します。

例A-5では、例A-4で作成したパッケージemp_actionsのテキストを選択し、プロシージャemp_actions.raise_salaryを起動します。パッケージ仕様部がラップされている場合、プロシージャを起動するために必要な情報は、パッケージ本体のPL/SQLソース・テキストのように判読不可能になります。

例A-4 CREATE_WRAPPEDプロシージャによるラップされたパッケージ本体の作成

DECLARE
  package_text  VARCHAR2(32767); -- text for creating package spec and body
 
  FUNCTION generate_spec (pkgname VARCHAR2) RETURN VARCHAR2 AS
  BEGIN
    RETURN 'CREATE PACKAGE ' || pkgname || ' AUTHID CURRENT_USER AS
      PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER);
      PROCEDURE fire_employee (emp_id NUMBER);
      END ' || pkgname || ';';
  END generate_spec;
 
  FUNCTION generate_body (pkgname VARCHAR2) RETURN VARCHAR2 AS
  BEGIN
    RETURN 'CREATE PACKAGE BODY ' || pkgname || ' AS
      PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER) IS
      BEGIN
        UPDATE employees
          SET salary = salary + amount WHERE employee_id = emp_id;
      END raise_salary;
      PROCEDURE fire_employee (emp_id NUMBER) IS
      BEGIN
        DELETE FROM employees WHERE employee_id = emp_id;
      END fire_employee;
    END ' || pkgname || ';';
  END generate_body;
 
BEGIN
  package_text := generate_spec('emp_actions');  -- Generate package spec
  EXECUTE IMMEDIATE package_text;                -- Create package spec
  package_text := generate_body('emp_actions');  -- Generate package body
  SYS.DBMS_DDL.CREATE_WRAPPED(package_text);     -- Create wrapped package body
END;
/

例A-5 ラップされた本体を含むパッケージの表示およびパッケージ・プロシージャの起動

パッケージのテキストの選択:

SELECT text FROM USER_SOURCE WHERE name = 'EMP_ACTIONS';

結果:

c
TEXT
------------------------------------------------------------------------
 
PACKAGE emp_actions AUTHID CURRENT_USER AS
      PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER);
      PROCEDURE fire_employee (emp_id NUMBER);
      END emp_actions;
PACKAGE BODY emp_actions wrapped
a000000
1f
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
b
180 113
1fOVodewm7j9dBOmBsiEQz0BKCgwg/BKoZ4VZy/pTBIYo8Uj1sjpbEz08Ck3HMjYq/Mf0XZn
u9D0Kd+i89g9ZO61I6vZYjw2AuBidnLESyR63LHZpFD/7lyDTfF1eDY5vmNwLTXrFaxGy243
0lHKAzmOlwwfBWylkZZNi2UnpmSIe6z/BU2nhbwfpqd224p69FwYVXmFX2H5IMsdZ2/vWsK9
cDMCD1KEqOnPpbU2yXdpW3GIbGD8JFIbKAfpJLkoLfVxoRPXQfj0h1k=

raised_salaryの起動およびその影響の表示:

DECLARE
  s employees.salary%TYPE;
BEGIN
  SELECT salary INTO s FROM employees WHERE employee_id=130;
  DBMS_OUTPUT.PUT_LINE('Old salary: ' || s);
  emp_actions.raise_salary(130, 100);
  SELECT salary INTO s FROM employees WHERE employee_id=130;
  DBMS_OUTPUT.PUT_LINE('New salary: ' || s);
END;
/

結果:

Old salary: 2800
New salary: 2900
 
PL/SQL procedure successfully completed.