6.4 パッケージのコール仕様の記述

PL/SQLパッケージは、論理的に関連のある型、項目、サブプログラムをグループ化するスキーマ・オブジェクトです。通常、パッケージには仕様部と本体の2つの部分があります。仕様部はアプリケーションに対するインタフェースで、型、定数、変数、例外、カーソルおよびサブプログラムを宣言して使用できるようにします。本体は、カーソルとサブプログラムを定義します。

SQL*Plusでは、次の構文を使用してPL/SQLパッケージを対話形式で定義できます。

CREATE [OR REPLACE] PACKAGE package_name
  [AUTHID {CURRENT_USER | DEFINER}] {IS | AS}
  [type_definition [type_definition] ...]
  [cursor_spec [cursor_spec] ...]
  [item_declaration [item_declaration] ...]
  [{subprogram_spec | call_spec} [{subprogram_spec | call_spec}]...]
END [package_name];

[CREATE [OR REPLACE] PACKAGE BODY package_name {IS | AS}
  [type_definition [type_definition] ...]
  [cursor_body [cursor_body] ...]
  [item_declaration [item_declaration] ...]
  [{subprogram_spec | call_spec} [{subprogram_spec | call_spec}]...]
[BEGIN
  sequence_of_statements]
END [package_name];]

仕様部にはパブリック宣言が保持されていて、アプリケーションで参照できます。本体には、実装の詳細とプライベート宣言が含まれており、これらはアプリケーションから隠されています。パッケージ本体の宣言部に続いて、オプションの初期化部があります。これには、パッケージ変数を初期化する文が記述されています。これは、初めてパッケージを参照するときに1回のみ実行されます。

パッケージ仕様部で宣言されるコール仕様に、パッケージ本体のサブプログラムと同じシグネチャ(つまり、名前とパラメータのリスト)は設定できません。パッケージ仕様部のすべてのサブプログラムをコール仕様として宣言する場合、パッケージ本体は必要ありません(カーソルを定義するか、初期化部を使用する場合を除きます)。

AUTHID句は、すべてのパッケージ・サブプログラムをその定義者(AUTHID DEFINER、デフォルト)と実行者(AUTHID CURRENT_USER)のどちらの権限を使用して実行するかを指定します。スキーマ・オブジェクトに対する未修飾の参照を定義者と実行者のどちらのスキーマで解決するかも指定します。

例6-5に、パッケージのコール仕様の例を示します。

例6-5 パッケージのコール仕様

新規部門の追加、部門の削除および部門の位置の変更を行うメソッドで構成されたJavaクラスDeptManagerについて考えます。addDept()メソッドは、データベースの順序番号を使用して次の部門番号を取得することに注意してください。これらの3つのメソッドは論理的に関連しているため、それらのコール仕様をPL/SQLパッケージにグループ化できます。

import java.sql.*;
import java.io.*;
import oracle.jdbc.*;

public class DeptManager
{
  public static void addDept (String deptName, String deptLoc) throws SQLException
  {
    Connection conn = DriverManager.getConnection("jdbc:default:connection:");
    String sql = "SELECT deptnos.NEXTVAL FROM dual";
    String sql2 = "INSERT INTO dept VALUES (?, ?, ?)";
    int deptID = 0;
    try
    {
      PreparedStatement pstmt = conn.prepareStatement(sql);
      ResultSet rset = pstmt.executeQuery();
      while (rset.next())
      {
        deptID = rset.getInt(1);
      }
      pstmt = conn.prepareStatement(sql2);
      pstmt.setInt(1, deptID);
      pstmt.setString(2, deptName);
      pstmt.setString(3, deptLoc);
      pstmt.executeUpdate();
      rset.close();
      pstmt.close();
    }
    catch (SQLException e)
    {
      System.err.println(e.getMessage());
    }
  }

  public static void dropDept (int deptID) throws SQLException
  {
    Connection conn = DriverManager.getConnection("jdbc:default:connection:");
    String sql = "DELETE FROM dept WHERE deptno = ?";
    try
    {
      PreparedStatement pstmt = conn.prepareStatement(sql);
      pstmt.setInt(1, deptID);
      pstmt.executeUpdate();
      pstmt.close();
    }
    catch (SQLException e)
    {
      System.err.println(e.getMessage());
    }
  }

  public static void changeLoc (int deptID, String newLoc) throws SQLException
  {
    Connection conn = DriverManager.getConnection("jdbc:default:connection:");
    String sql = "UPDATE dept SET loc = ? WHERE deptno = ?";
    try
    {
      PreparedStatement pstmt = conn.prepareStatement(sql);
      pstmt.setString(1, newLoc);
      pstmt.setInt(2, deptID);
      pstmt.executeUpdate();
      pstmt.close();
    }
    catch (SQLException e)
    {
      System.err.println(e.getMessage());
    }
  }
}

addDept()dropDept()およびchangeLoc()メソッドをパッケージ化するとします。最初に、次のようにパッケージ仕様部を作成する必要があります。

CREATE OR REPLACE PACKAGE dept_mgmt AS
PROCEDURE add_dept (dept_name VARCHAR2, dept_loc VARCHAR2);
PROCEDURE drop_dept (dept_id NUMBER);
PROCEDURE change_loc (dept_id NUMBER, new_loc VARCHAR2);
END dept_mgmt;

次に、Javaメソッドのコール仕様を次のように記述してパッケージ本体を作成する必要があります。

CREATE OR REPLACE PACKAGE BODY dept_mgmt AS
PROCEDURE add_dept (dept_name VARCHAR2, dept_loc VARCHAR2)
AS LANGUAGE JAVA
NAME 'DeptManager.addDept(java.lang.String, java.lang.String)';

PROCEDURE drop_dept (dept_id NUMBER)
AS LANGUAGE JAVA
NAME 'DeptManager.dropDept(int)';

PROCEDURE change_loc (dept_id NUMBER, new_loc VARCHAR2)
AS LANGUAGE JAVA
NAME 'DeptManager.changeLoc(int, java.lang.String)';
END dept_mgmt;

dept_mgmtパッケージのストアド・プロシージャを参照するには、次のように、ドット表記法を使用します。

CALL dept_mgmt.add_dept('PUBLICITY', 'DALLAS');