ヘッダーをスキップ
Oracle Database PL/SQL言語リファレンス
11g リリース1(11.1)
E05670-03
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

10 PL/SQLパッケージの使用

この章では、互いに関連するPL/SQLコードとデータを1つのパッケージにまとめる方法について説明します。 パッケージをコンパイルしてデータベースに格納し、その内容を複数のアプリケーションで共有できます。

ここでのトピック:

PL/SQLパッケージ

パッケージとは、論理的に関連するPL/SQLの型、変数およびサブプログラムをグループにまとめたスキーマ・オブジェクトのことです。 通常、パッケージは仕様部と本体の2つの部分で構成されますが、本体が不要な場合もあります。

仕様部はパッケージへのインタフェースです。 ここでは、型、変数、定数、例外、カーソル、およびパッケージの外から参照できるサブプログラムを宣言します。 本体は、カーソルの問合せとサブプログラムのコードを定義します。

仕様部はインタフェース、本体はブラック・ボックスと考えることができます。 パッケージの仕様部を変更しなくても、本体をデバッグ、拡張または置換できます。

パッケージ仕様部を作成するには、CREATE PACKAGE文を使用します。 パッケージ本体を作成するには、CREATE PACKAGE BODY文を使用します。

仕様部には、ストアド・サブプログラムやその他のパッケージ外部のコードから見えるパブリックな宣言を入れます。 サブプログラムは、仕様部で他のすべての項目の後で最後に宣言する必要があります(ただし、特定のファンクションの名前を指定するプラグマは、ファンクション仕様部の後に宣言する必要があります)。

本体には、実装の細部と、パッケージ外部のコードからは隠されているプライベートな宣言を入れます。 パッケージ本体の宣言部の後には、オプションの初期化部があります。ここには、パッケージ変数を初期化する文と、その他の一度のみの設定を行う文を入れます。

AUTHID句は、すべてのパッケージ・サブプログラムがその定義者(デフォルト)と実行者のどちらの権限で実行するか、およびスキーマ・オブジェクトへの未修飾の参照が定義者と実行者のどちらのスキーマで解決されるかを決定します。 詳細は、「実行者権限または定義者権限の使用(AUTHID句)」を参照してください。

コール仕様を使用すると、パッケージ・サブプログラムをJavaメソッドまたは外部Cファンクションにマップできます。 コール仕様は、JavaまたはC言語の名前、パラメータ型および戻り型を対応するSQLにマップします。


参照:

  • Javaコール仕様を作成する方法は、『Oracle Database Java開発者ガイド』を参照してください。

  • Cコール仕様を作成する方法は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』を参照してください。

  • Oracleで提供されているPL/SQLパッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。


PL/SQLパッケージの内容

PL/SQLパッケージには、次のものが含まれています。

詳細は、「CREATE PACKAGE文」を参照してください。 PL/SQLパッケージの例は、例1-19および例10-3を参照してください。 アプリケーションから参照およびアクセスできるのは、パッケージ仕様部の宣言のみです。 パッケージ本体の実装の詳細は隠ぺいされ、アクセスできません。 そのため、起動元のプログラムを再コンパイルしなくても、本体(実装)を変更できます。

PL/SQLパッケージのメリット

ソフトウェア・エンジニアリングではパッケージに長い歴史があります。大規模なシステムのチーム開発において、パッケージは信頼性のある、メンテナンスが容易で再利用可能なコードに重要な機能を提供しています。

モジュール性

パッケージを使用すると、論理的に関連した型、項目およびサブプログラムを、名前付きのPL/SQLモジュールにカプセル化できます。 個々のパッケージは理解しやすく、パッケージ間のインタフェースは単純かつ明快で、明確に定義されています。 これはアプリケーション開発に役立ちます。

アプリケーションの設計の容易さ

アプリケーション設計の最初の段階では、パッケージの仕様部に含まれるインタフェース情報のみが必要です。 仕様部は本体がなくてもコーディングし、コンパイルできます。 仕様部のコンパイルが終了すると、そのパッケージを参照するストアド・サブプログラムもコンパイルできます。 アプリケーション作成の最終段階になるまで、パッケージ本体を完全に定義する必要はありません。

情報の隠ぺい

パッケージを使用すると、個々の型、項目およびサブプログラムについて、それがパブリック(可視でアクセス可能)なのか、またはプライベート(隠されていてアクセス不可)なのかを指定できます。 たとえば、パッケージに含まれる4つのサブプログラムのうち、3つをパブリック、1つをプライベートにすることもできます。 パッケージはプライベートなサブプログラムの実装を隠ぺいするため、実装が変更された場合も(アプリケーションではなく)パッケージのみが影響を受けます。 このため、メンテナンスや機能拡張が簡単に実施できます。 また、実装上の細部をユーザーから隠ぺいすることで、パッケージの整合性を維持できます。

機能の追加

パッケージ化されたパブリック変数およびカーソルは、セッションを通じて存続します。 このため、同じ環境の中で実行するすべてのサブプログラムで共有できます。 これによって、データベースに格納することなくトランザクション間でデータをメンテナンスできます。

高いパフォーマンス

パッケージ・サブプログラムを初めて起動すると、パッケージ全体がメモリーにロードされます。 パッケージ内の関連するサブプログラムに対する2度目以降のコールでは、ディスクI/Oは必要ありません。

パッケージ化すると互いに依存することがなくなるため、不要な再コンパイルを避けることができます。 たとえば、パッケージ・ファンクションの本体を変更した場合、そのファンクションを起動する他のサブプログラムはデータベースによって再コンパイルされません。これらのサブプログラムは仕様部で宣言されたパラメータと戻り値にのみ依存するためです。再コンパイルされるのは、仕様部が変更された場合のみです。

PL/SQLパッケージ仕様部の理解

パッケージ仕様部にはパブリック宣言が入っています。 宣言された項目は、パッケージ内のどの場所からでも、同じスキーマ内の別のサブプログラムからでもアクセス可能です。 図10-1に有効範囲を示します。

図10-1 パッケージの有効範囲

パッケージの有効範囲
「図10-1 パッケージの有効範囲」の説明

仕様部には、アプリケーションが利用できるパッケージ・リソースのリストがあります。 アプリケーションがリソースを使用するために必要な情報は、すべて仕様部の中にあります。 たとえば、次の宣言は、factorialという名前のファンクションがINTEGER型の引数を1つ取り、INTEGER型の値を戻すことを示しています。

FUNCTION factorial (n INTEGER) RETURN INTEGER; -- returns n!

ファンクションの起動に必要な情報はこれのみです。 ユーザーはfacの下位の実装のこと(それが反復を利用しているのか、再帰を利用しているのかなど)を考える必要がありません。

仕様部で宣言されているのが型、定数、変数、例外およびコール仕様のみであれば、パッケージ本体は不要です。 下位の実装を持つのは、サブプログラムとカーソルのみです。 例10-1では、パッケージは型、例外および変数を宣言していますが、サブプログラムまたはカーソルを持たないため、パッケージ本体は不要です。 このようなパッケージを使用すると、セッションを通じて存続するグローバル変数(ストアド・サブプログラムおよびトリガーで使用できる)を定義できます。

例10-1 単純なパッケージ仕様部(本体なし)

CREATE PACKAGE trans_data AS  -- bodiless package
   TYPE TimeRec IS RECORD (
      minutes SMALLINT,
      hours   SMALLINT);
   TYPE TransRec IS RECORD (
      category VARCHAR2(10),
      account  INT,
      amount   REAL,
      time_of  TimeRec);
   minimum_balance    CONSTANT REAL := 10.00;
   number_processed   INT;
   insufficient_funds EXCEPTION;
END trans_data;
/

PL/SQLパッケージの内容の参照

パッケージの仕様部で宣言された型、項目、サブプログラムおよびコール仕様部を参照するときには、次のようにドット表記法を使用します。

package_name.type_name
package_name.item_name
package_name.subprogram_name
package_name.call_spec_name

パッケージ内容は、データベース・トリガー、ストアド・サブプログラム、3GLアプリケーション・プログラムおよび様々なOracleのツール製品から参照できます。 たとえば、例1-20または例10-3で示すように、パッケージ・サブプログラムを起動できます。

次の例では、Pro*Cプログラムの無名ブロックからhire_employeeプロシージャを起動しています。 実パラメータemp_idemp_lnameおよびemp_fnameはホスト変数です。

EXEC SQL EXECUTE
  BEGIN
    emp_actions.hire_employee(:emp_id,:emp_lname,:emp_fname, ...);

制限

リモート・パッケージ変数は、直接的にも間接的にも参照できません。 たとえば、サブプログラムがパッケージ変数を参照する場合、データベース・リンクを通じてサブプログラムを起動することはできません。

また、パッケージ内ではホスト変数を参照できません。

PL/SQLパッケージ本体の理解

パッケージ本体には、パッケージ仕様部で宣言されているすべてのカーソルとサブプログラムの実装が含まれています。 パッケージ本体で定義されたサブプログラムにパッケージの外側からアクセスするには、その指定がパッケージ仕様部に存在している必要があります。 サブプログラムの仕様部がパッケージ仕様部に含まれていない場合、サブプログラムは同じパッケージ内の他のサブプログラムからのみ起動できます。 パッケージ本体は、パッケージ仕様部と同じスキーマ内にある必要があります。

サブプログラムの仕様部と本体を一致させるために、PL/SQLは、それらのヘッダーをトークンごとに比較します。 このため、空白を除いて、ヘッダーは一語一語が一致している必要があります。 一致していない場合、PL/SQLは、例10-2に示すように、例外を呼び出します。

例10-2 パッケージの仕様部と本体の一致

CREATE PACKAGE emp_bonus AS
   PROCEDURE calc_bonus (date_hired employees.hire_date%TYPE);
END emp_bonus;
/
CREATE PACKAGE BODY emp_bonus AS
-- the following parameter declaration raises an exception
-- because 'DATE' does not match employees.hire_date%TYPE
-- PROCEDURE calc_bonus (date_hired DATE) IS
-- the following is correct because there is an exact match
   PROCEDURE calc_bonus
     (date_hired employees.hire_date%TYPE) IS
   BEGIN
     DBMS_OUTPUT.PUT_LINE
       ('Employees hired on ' || date_hired || ' get bonus.');
   END;
END emp_bonus;
/

パッケージ本体には、パッケージの内部動作に必要な型や項目を定義するプライベート宣言を入れることもできます。 これらの宣言の有効範囲は、パッケージ本体に対してローカルです。 このため、宣言された型と項目はパッケージ本体の中からでなければアクセスできません。 パッケージ仕様部とは異なり、パッケージ本体の宣言部にはサブプログラムの本体を置くことができます。

パッケージ本体の宣言部の後には、オプションの初期化部があります。ここには、一般にパッケージの中で宣言済の変数を初期化する文がいくつか置かれています。

サブプログラムとは異なり、パッケージを起動することもパッケージにパラメータを渡すこともできないため、パッケージの初期化部にはあまり意味がありません。 このため、パッケージの初期化部は、パッケージが初めて参照されたときに一度のみ実行されます。

すでに説明したように、仕様部で宣言されているのが型、定数、変数、例外およびコール仕様部のみであればパッケージ本体は不要です。 ただしその場合でも、パッケージ本体を使用して、パッケージ仕様部で宣言した項目を初期化できます。

PL/SQLパッケージ機能の例

次に示すemp_adminという名前のパッケージの例を考えます。 パッケージ仕様部では、次のような型、項目およびサブプログラムを宣言します。

パッケージを作成すると、そのパッケージの型の参照、サブプログラムの起動、カーソルの使用、例外の呼出しなどを行うアプリケーションを開発できます。 パッケージを作成すると、そのパッケージはデータベースに格納され、そのパッケージの実行権限を持つアプリケーションから使用されます。

例10-3 emp_adminパッケージの作成

-- create the audit table to track changes
CREATE TABLE emp_audit(date_of_action DATE, user_id VARCHAR2(20),
                       package_name VARCHAR2(30));

CREATE OR REPLACE PACKAGE emp_admin AS
-- Declare externally visible types, cursor, exception
   TYPE EmpRecTyp IS RECORD (emp_id NUMBER, sal NUMBER);
   CURSOR desc_salary RETURN EmpRecTyp;
   invalid_salary EXCEPTION;
-- Declare externally callable subprograms
   FUNCTION hire_employee (last_name VARCHAR2,
                           first_name VARCHAR2,
                           email VARCHAR2,
                           phone_number VARCHAR2,
                           job_id VARCHAR2,
                           salary NUMBER,
                           commission_pct NUMBER,
                           manager_id NUMBER,
                           department_id NUMBER)
     RETURN NUMBER;
   PROCEDURE fire_employee
     (emp_id NUMBER); -- overloaded subprogram
   PROCEDURE fire_employee
     (emp_email VARCHAR2); -- overloaded subprogram
   PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER);
   FUNCTION nth_highest_salary (n NUMBER) RETURN EmpRecTyp;
END emp_admin;
/
CREATE OR REPLACE PACKAGE BODY emp_admin AS
   number_hired NUMBER;  -- visible only in this package
-- Fully define cursor specified in package
   CURSOR desc_salary RETURN EmpRecTyp IS
      SELECT employee_id, salary
      FROM employees
      ORDER BY salary DESC;
-- Fully define subprograms specified in package
   FUNCTION hire_employee (last_name VARCHAR2,
                           first_name VARCHAR2,
                           email VARCHAR2,
                           phone_number VARCHAR2,
                           job_id VARCHAR2,
                           salary NUMBER,
                           commission_pct NUMBER,
                           manager_id NUMBER,
                           department_id NUMBER)
     RETURN NUMBER IS new_emp_id NUMBER;
   BEGIN
      new_emp_id := employees_seq.NEXTVAL;
      INSERT INTO employees VALUES (new_emp_id,
                                    last_name,
                                    first_name,
                                    email,
                                    phone_number,
                                    SYSDATE,
                                    job_id,
                                    salary,
                                    commission_pct,
                                    manager_id,
                                    department_id);
      number_hired := number_hired + 1;
      DBMS_OUTPUT.PUT_LINE('The number of employees hired is '
                           || TO_CHAR(number_hired) );
      RETURN new_emp_id;
   END hire_employee;
   PROCEDURE fire_employee (emp_id NUMBER) IS
   BEGIN
      DELETE FROM employees WHERE employee_id = emp_id;
   END fire_employee;
   PROCEDURE fire_employee (emp_email VARCHAR2) IS
   BEGIN
      DELETE FROM employees WHERE email = emp_email;
   END fire_employee;
  -- Define local function, available only inside package
   FUNCTION sal_ok (jobid VARCHAR2, sal NUMBER) RETURN BOOLEAN IS
      min_sal NUMBER;
      max_sal NUMBER;
   BEGIN
      SELECT MIN(salary), MAX(salary)
        INTO min_sal, max_sal
        FROM employees
        WHERE job_id = jobid;
      RETURN (sal >= min_sal) AND (sal <= max_sal);
   END sal_ok;
   PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER) IS
      sal NUMBER(8,2);
      jobid VARCHAR2(10);
   BEGIN
      SELECT job_id, salary INTO jobid, sal
        FROM employees
        WHERE employee_id = emp_id;
      IF sal_ok(jobid, sal + amount) THEN
         UPDATE employees SET salary =
           salary + amount WHERE employee_id = emp_id;
      ELSE
         RAISE invalid_salary;
      END IF;
   EXCEPTION  -- exception-handling part starts here
     WHEN invalid_salary THEN
       DBMS_OUTPUT.PUT_LINE
         ('The salary is out of the specified range.');
   END raise_salary;
   FUNCTION nth_highest_salary (n NUMBER) RETURN EmpRecTyp IS
      emp_rec EmpRecTyp;
   BEGIN
      OPEN desc_salary;
      FOR i IN 1..n LOOP
         FETCH desc_salary INTO emp_rec;
      END LOOP;
      CLOSE desc_salary;
      RETURN emp_rec;
   END nth_highest_salary;
BEGIN  -- initialization part starts here
   INSERT INTO emp_audit VALUES (SYSDATE, USER, 'EMP_ADMIN');
   number_hired := 0;
END emp_admin;
/
-- invoking the package procedures
DECLARE
  new_emp_id NUMBER(6);
BEGIN
  new_emp_id := emp_admin.hire_employee ('Belden',
                                         'Enrique',
                                         'EBELDEN',
                                         '555.111.2222',
                                         'ST_CLERK',
                                         2500,
                                         .1,
                                         101,
                                         110);
  DBMS_OUTPUT.PUT_LINE
    ('The new employee id is ' || TO_CHAR(new_emp_id));
  EMP_ADMIN.raise_salary(new_emp_id, 100);
  DBMS_OUTPUT.PUT_LINE('The 10th highest salary is '||
    TO_CHAR(emp_admin.nth_highest_salary(10).sal) || ',
            belonging to employee: ' ||
            TO_CHAR(emp_admin.nth_highest_salary(10).emp_id));
  emp_admin.fire_employee(new_emp_id);
-- you can also delete the newly added employee as follows:
--  emp_admin.fire_employee('EBELDEN');
END;
/

パッケージの初期化部は、パッケージが初めて参照されたときに一度のみ実行されることに注意してください。 このため、上の例のINSERT文では、データベース表emp_auditに挿入される行は1行のみです。また、変数number_hiredは一度しか初期化されません。

プロシージャhire_employeeが起動されるたびに、変数number_hiredが更新されます。 ただし、number_hiredが保持しているカウントは各セッションによって異なります。 つまり、カウントは全ユーザーが処理した数ではなく、1人のユーザーが処理した新しい従業員の数を反映します。

PL/SQLでは、パッケージ化された複数のサブプログラムに同じ名前を付けることができます。 サブプログラムで、データ型が異なるパラメータからなる類似したパラメータのセットを受け取れるようにする場合は、この方法が便利です。 たとえば、例10-3emp_adminパッケージではfire_employeeという名前の2つのプロシージャを定義しています。 1番目のプロシージャは数値を受け取り、2番目のプロシージャは文字列を受け取ります。 ただし、どちらのプロシージャもデータを適切に処理します。 オーバーロードされたサブプログラムに適用される規則は、「PL/SQLサブプログラム名のオーバーロード」を参照してください。

PL/SQLパッケージのプライベート項目とパブリック項目

パッケージemp_adminのパッケージ本体では、0(ゼロ)に初期化される変数number_hiredが宣言されています。 本体で宣言される項目は、パッケージ内でしか使用できません。 このため、パッケージの外側のPL/SQLコードからは変数number_hiredを参照できません。 このような項目はプライベートと呼ばれます。

例外emp_adminなど、invalid_salaryの仕様部で宣言された項目は、パッケージの外からも見えます。 このため、例外invalid_salaryはどのPL/SQLコードからも参照できます。 このような項目はパブリックと呼ばれます。

セッションを通じて、または複数のトランザクションの間で維持する必要がある項目は、パッケージ本体の宣言部に置くようにしてください。 たとえば、number_hiredの値はhire_employeeへの複数のコールの間も保持されています。 セッションが終了すると、値が失われます。

パブリックにする必要がある項目は、パッケージ仕様部の中に置いてください。 たとえば、パッケージ仕様部で宣言されたemp_recは、パブリックで使用可能です。

STANDARDパッケージによるPL/SQL環境の定義

STANDARDという名前のパッケージではPL/SQL環境を定義しています。 このパッケージの仕様部では、型、例外およびサブプログラムをグローバルに宣言します。それらは、自動的にPL/SQLプログラムで使用可能になります。 たとえば、パッケージSTANDARDでは、引数の絶対値を戻すファンクションABSを次のように宣言します。

FUNCTION ABS (n NUMBER) RETURN NUMBER;

パッケージSTANDARDの内容は、アプリケーションから直接見ることができます。 その内容を参照する場合もパッケージ名に接頭辞を付けて修飾名にする必要はありません。 たとえば、ABSはデータベース・トリガー、ストアド・サブプログラム、Oracleのツール製品または3GLアプリケーションから次のように起動できます。

abs_diff := ABS(x - y);

ユーザー独自のABSを宣言すると、ローカル宣言がグローバル宣言をオーバーライドします。 ただし、次に示すように、完全な名前を指定して、組込みファンクションを起動できます。

abs_diff := STANDARD.ABS(x - y);

ほとんどの組込みファンクションはオーバーロードされています。 たとえば、パッケージSTANDARDには次のような宣言があります。

FUNCTION TO_CHAR (right DATE) RETURN VARCHAR2;
FUNCTION TO_CHAR (left NUMBER) RETURN VARCHAR2;
FUNCTION TO_CHAR (left DATE, right VARCHAR2) RETURN VARCHAR2;
FUNCTION TO_CHAR (left NUMBER, right VARCHAR2) RETURN VARCHAR2;

PL/SQLは、仮パラメータと実パラメータの数とデータ型を比較して、どのTO_CHARのコールかを判定します。

製品固有のPL/SQLパッケージの概要

Oracleの様々なツール製品には、PL/SQL、SQL、Javaまたはその他のプログラミング環境から起動できるApplication Program Interface(API)を定義した製品固有のパッケージが用意されています。 この項では、広く使用されている次の製品固有のパッケージについて簡単に説明します。

これらの製品固有のパッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

DBMS_ALERTパッケージ

DBMS_ALERTパッケージでは、データベース内の特定の値が変更されたときに、データベース・トリガーを使用してアプリケーションに警告できます。 その警告は、トランザクション・ベースで、非同期です(つまり、警告はタイミング・メカニズムとは無関係に作動します)。 たとえば、会社ではこのパッケージを使用して、株や債券の取り引き価格が更新されたときに、投資ポートフォリオの値を更新できます。

DBMS_OUTPUTパッケージ

DBMS_OUTPUTパッケージを使用すると、PL/SQLブロック、サブプログラム、パッケージおよびトリガーからの出力を表示できます。 このパッケージは、PL/SQLデバッグ情報を表示する場合に特に役立ちます。 PUT_LINEプロシージャは、別のトリガー、サブプログラムまたはパッケージで読み取ることができるバッファに情報を出力します。 この情報は、プロシージャGET_LINEを起動するか、SQL*PlusにSERVEROUTPUT ONを設定することによって表示します。 例10-4に、PL/SQLブロックからの出力の表示方法を示します。

例10-4 DBMS_OUTPUTパッケージでのPUT_LINEの使用

REM set server output to ON to display output from DBMS_OUTPUT
SET SERVEROUTPUT ON
BEGIN
  DBMS_OUTPUT.PUT_LINE
    ('These are the tables that ' || USER || ' owns:');
  FOR item IN (SELECT table_name FROM user_tables)
    LOOP
      DBMS_OUTPUT.PUT_LINE(item.table_name);
    END LOOP;
END;
/

DBMS_PIPEパッケージ

DBMS_PIPEパッケージを使用すると、名前付きパイプを介して異なるセッション間で通信できます。 (パイプとは、あるプロセスから他のプロセスに情報を渡すために使用するメモリーの領域のことです。) PACK_MESSAGEプロシージャとSEND_MESSAGEプロシージャを使用してパイプの中にメッセージをパックし、同じインスタンス内の別のセッションまたは待機中のアプリケーション(Linux、UNIXプログラムなど)に送信できます。

パイプのもう一端では、RECEIVE_MESSAGEプロシージャとUNPACK_MESSAGEプロシージャを使用して、メッセージを受信し、アンパック(読取り)できます。 名前付きパイプは、あらゆる点で便利です。 たとえば、データを収集するCプログラムを作成し、次にそれをパイプを介してデータベース内のストアド・サブプログラムに送信できます。

DBMS_CONNECTION_POOLパッケージ

DBMS_CONNECTION_POOLパッケージは、複数の中間層プロセスによって共有されるデータベース常駐接続プールの管理に使用されます。 データベース管理者は、DBMS_CONNECTION_POOLのプロシージャを使用して、データベース常駐接続プールの開始と停止、およびサイズや時間制限などのプール・パラメータの構成を行います。


参照:

  • DBMS_CONNECTION_POOLパッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

  • データベース常駐接続プールの管理の詳細は、『Oracle Database管理者ガイド』を参照してください。


HTFパッケージおよびHTPパッケージ

HTFパッケージおよびHTPパッケージを使用すると、PL/SQLプログラムでHTMLタグを生成できます。

UTL_FILEパッケージ

UTL_FILEパッケージを使用すると、PL/SQLプログラムでオペレーティング・システム(OS)のテキスト・ファイルに対して読取りおよび書込みを実行できます。 このパッケージは、オペレーティング・システムの標準ストリーム・ファイルI/Oの制限されたバージョン(OPEN、PUT、GET、CLOSEの操作を含む)を提供します。

テキスト・ファイルに対して読取りまたは書込みを実行する場合は、ファンクションFOPENを起動します。このファンクションは、それ以降のサブプログラム・コールで使用するためのファイル・ハンドルを戻します。 たとえば、プロシージャPUT_LINEは、テキスト文字列と行終了文字をオープン・ファイルに書き込みます。また、プロシージャGET_LINEは、オープン・ファイルから出力バッファにテキストの行を読み込みます。

UTL_HTTPパッケージ

UTL_HTTPパッケージを使用すると、PL/SQLプログラムでHTTP(Hypertext Transfer Protocol)のコールアウトを実行できます。 これによって、データをインターネットから取り出すことも、Oracle Web Serverカートリッジを起動することもできます。 このパッケージには複数のエントリ・ポイントがあり、各ポイントでURL(Uniform Resource Locator)を受け取り、指定されたサイトに接続し、要求されたデータを戻します。通常このデータはHTML(Hypertext Markup Language)形式のものです。

UTL_SMTPパッケージ

UTL_SMTPパッケージを使用すると、PL/SQLプログラムでSimple Mail Transfer Protocol(SMTP)を介して電子メールを送信できます。 パッケージには、電子メール・クライアントのSMTPコマンドへのインタフェースがあり、電子メールをSMTPサーバーにディスパッチします。

PL/SQLパッケージ作成のガイドライン

パッケージを作成する場合は、別のアプリケーションで再利用できるように、汎用性を持たせるようにしてください。 オラクル社が提供するパッケージをよく理解して、すでにOracleが提供している機能と重複する機能を持つパッケージを作成しないように注意してください。

パッケージ本体の前にパッケージ仕様部を設計および定義してください。 仕様部に入れるのは、起動元のプログラムから見える必要のあるもののみにします。 こうすることで、他の開発者が実装の細部に不適切に依存しないようにできます。

コードの変更時に必要な再コンパイルを削減するために、パッケージ仕様部に置く項目はできるかぎり少なくしておきます。 そうすれば、パッケージ本体を変更しても、起動元のサブプログラムを再コンパイルする必要はありません。 ただし、パッケージ仕様部を変更すると、データベースでそのパッケージを参照するすべてのストアド・サブプログラムを再コンパイルする必要があります。

PL/SQLパッケージでのカーソル仕様部と本体の分離

パッケージの中で、カーソルの仕様部を本体と切り離して別の位置に配置できます。 これによって、カーソルの仕様部を変更せずに、本体のみを変更できます。 カーソルの構文は、「明示カーソル」を参照してください。

例10-5では、%ROWTYPE属性を使用して、データベース表employeesの中の行を表すレコード型を指定しています。

例10-5 パッケージでのカーソル仕様部の分離

CREATE PACKAGE emp_stuff AS
  -- Declare cursor spec
  CURSOR c1 RETURN employees%ROWTYPE;
END emp_stuff;
/
CREATE PACKAGE BODY emp_stuff AS
  CURSOR c1 RETURN employees%ROWTYPE IS
    -- Define cursor body
    SELECT * FROM employees WHERE salary > 2500;
END emp_stuff;
/

戻り値のデータ型をSELECT句で指定しているため、カーソル仕様部にはRETURN文がありません。 ただしカーソル本体には、SELECT文と、カーソル仕様部と同じRETURN句が必要です。 また、SELECTリスト中の項目の数とデータ型は、RETURN句と一致する必要があります。

パッケージ・カーソルを使用すると柔軟性が向上します。 たとえば、上の例では、カーソル仕様部を変更することなく、カーソル本体を変更できます。

次の例に示すように、PL/SQLブロックまたはサブプログラムからパッケージ・カーソルを参照するドット表記法を使用します。

DECLARE   emp_rec employees%ROWTYPE;BEGIN
   OPEN emp_stuff.c1;
   LOOP
      FETCH emp_stuff.c1 INTO emp_rec;
-- do processing here ...
      EXIT WHEN emp_stuff.c1%NOTFOUND;
   END LOOP;
   CLOSE emp_stuff.c1;
END;
/

パッケージ・カーソルの有効範囲はPL/SQLブロックに制限されません。 したがって、パッケージ・カーソルをオープンすると、クローズするか、セッションから切断するまでオープンしたままになります。