JavaでREFカーソルを使用する

A REF CURSOR is a cursor variable that contains a pointer to a query result set returned by an OPEN statement. Unlike a static cursor, a REF CURSOR is not tied to a particular query. You may open the same REF CURSOR variable any number of times with the OPEN statement containing different queries; each time, a new result set is created for that query and made available via the cursor variable. A REF CURSOR can also pass a result set from one procedure to another.

AdvancedServerは、 strongly-typed と weakly-typed REF CURSORs の両方の宣言をサポートしています。強く型付けされたカーソルは、予想される結果セットの shape (各列の型)を宣言する必要があります。厳密に型指定されたカーソルは、宣言された列を返すクエリでのみ使用できます。異なる形状の結果セットを返すクエリでカーソルを開くと、サーバーは例外をスローします。一方、弱い型指定のカーソルは、任意の形状の結果セットで機能します。

強く型付けされた REF CURSOR を宣言するには:

TYPE <cursor_type_name> IS REF CURSOR RETURN <return_type>;

弱い型付けの REF_CURSOR を宣言するには:

name SYS_REFCURSOR;

.. raw:: latex

  \newpage

REFCURSORを使用してResultSetを取得する

The stored procedure shown in Listing 1.11-a (getEmpNames) builds two REF CURSORs on the server; the first REF CURSOR contains a list of commissioned employees in the emp table, while the second REF CURSOR contains a list of salaried employees in the emp table:

リスト1.11-a

CREATE OR REPLACE PROCEDURE getEmpNames
(
  commissioned IN OUT SYS_REFCURSOR,
  salaried IN OUT SYS_REFCURSOR
)
IS
BEGIN
  OPEN commissioned FOR SELECT ename FROM emp WHERE comm is NOT NULL;
  OPEN salaried FOR SELECT ename FROM emp WHERE comm is NULL;
END;

RefCursorSample() メソッド(リスト1.11-bを参照)は getEmpName() ストアドプロシージャを呼び出し、2つの REF CURSOR 変数のそれぞれに返された名前を表示します。

リスト1.11-b

public void RefCursorSample(Connection con)
{
  try
  {
    con.setAutoCommit(false);
    String commandText = "{call getEmpNames(?,?)}";
    CallableStatement stmt = con.prepareCall(commandText);
    stmt.setNull(1, Types.REF);
    stmt.registerOutParameter(1, Types.REF);
    stmt.setNull(2, Types.REF);
    stmt.registerOutParameter(2, Types.REF);

    stmt.execute();
    ResultSet commissioned = (ResultSet)stmt.getObject(1);
    System.out.println("Commissioned employees:");
    while(commissioned.next())
    {
      System.out.println(commissioned.getString(1));
    }

    ResultSet salaried = (ResultSet)stmt.getObject(2);
    System.out.println("Salaried employees:");
    while(salaried.next())
    {
      System.out.println(salaried.getString(1));
    }
  }
  catch(Exception err)
  {
    System.out.println("An error has occurred.");
    System.out.println("See full details below.");
    err.printStackTrace();
  }
}

CallableStatement は各 REF CURSOR ( commissioned と salaried )を準備します。各カーソルは、ストアドプロシージャ getEmpNames() の IN OUT パラメーターとして返されます。

String commandText = "{call getEmpNames(?,?)}";
CallableStatement stmt = con.prepareCall(commandText);

registerOutParameter() への呼び出しは、最初のREFCURSOR(委託)のパラメータータイプ(Types.REF)を登録します。

stmt.setNull(1, Types.REF);
stmt.registerOutParameter(1, Types.REF);

registerOutParameter() への別の呼び出しは、2番目の REF CURSOR (salaried) の2番目のパラメーター型( Types.REF )を登録します:

stmt.setNull(2, Types.REF);
stmt.registerOutParameter(2, Types.REF);

stmt.execute() への呼び出しはステートメントを実行します:

stmt.execute();

getObject() メソッドは、最初のパラメーターから値を取得し、結果を ResultSet にキャストします。次に、 RefCursorSample はカーソルを反復処理し、各委託従業員の名前を出力します。

ResultSet commissioned = (ResultSet)stmt.getObject(1);
while(commissioned.next())
{
  System.out.println(commissioned.getString(1));
}

同じゲッターメソッドは、2番目のパラメーターから ResultSet を取得し、そのカーソルを介して RefCursorExample を繰り返し、給与を受け取る各従業員の名前を出力します。

ResultSet salaried = (ResultSet)stmt.getObject(2);
while(salaried.next())
{
  System.out.println(salaried.getString(1));
}