7.3 トップレベルのコール仕様の作成
SQL*Plusでは、次の構文を使用してトップレベルのコール仕様を対話形式で定義できます。
CREATE [OR REPLACE]
{ PROCEDURE procedure_name [(param[, param]...)]
| FUNCTION function_name [(param[, param]...)] RETURN sql_type}
[AUTHID {DEFINER | CURRENT_USER}]
[PARALLEL_ENABLE]
[DETERMINISTIC]
{IS | AS} LANGUAGE JAVA
NAME 'method_fullname (java_type_fullname[, java_type_fullname]...)
[return java_type_fullname]';
paramは次の構文で表されます。
                  
parameter_name [IN | OUT | IN OUT] sql_type
- 
                        ストアド・プロシージャをその定義者( AUTHID DEFINER)または実行者(AUTHID CURRENT_USER)のどちらの権限を使用して実行するか
- 
                        スキーマ・オブジェクトに対する未修飾の参照を定義者と実行者のどちらのスキーマで解決するか 
 AUTHIDを指定しない場合、デフォルトの動作はDEFINERになり、つまり、ストアド・プロシージャは定義者の権限で実行されます。AUTHIDにCURRENT_USERを指定して、デフォルトの動作をオーバーライドできます。ただし、CURRENT_USERを指定してloadjavaの-definerオプションをオーバーライドすることはできません。
                  
PARALLEL_ENABLEオプションは、ストアド・ファンクションをパラレルDML評価のスレーブ・セッションで安全に使用できることを宣言します。メイン・セッションの状態は、スレーブ・セッションとは共有されません。各スレーブ・セッションには独自の状態があり、セッションの開始時に初期化されます。ファンクションの結果はセッション変数の状態に依存する必要はありません。依存すると、セッション間で結果が異なることがあります。
                  
DETERMINISTICオプションは、オプティマイザによる冗長なファンクション・コールの回避に役立ちます。以前に同じ引数を使用してストアド・ファンクションがコールされた場合、オプティマイザは以前の結果を使用できます。ファンクションの結果はセッション変数またはスキーマ・オブジェクトの状態に依存する必要はありません。依存すると、コール間で結果が異なることがあります。ファンクション索引、またはクエリー・リライトが可能なマテリアライズド・ビューからのみDETERMINISTICファンクションをコールできます。
                  
NAME句の文字列は、Javaメソッドを一意に識別します。Javaの完全修飾名とコール仕様パラメータは、位置によってマッピングされ、対応する必要があります。ただし、この規則はmain()メソッドには適用されません。Javaメソッドが引数を取らない場合は、ファンクションまたはプロシージャ用ではなく、Javaメソッド用の空のパラメータ・リストを作成してください。
                  
Javaの完全修飾名はドット表記法を使用して記述します。次の例では、完全修飾名はドットで区切り、行をまたいで記述できることを示しています。
artificialIntelligence.neuralNetworks.patternClassification. RadarSignatureClassifier.computeRange()
7.3.1 例
例7-1 簡単なJDBCストアド・プロシージャの公開
次のJavaクラスの実行可能ファイルがデータベースにロードされたとします。
import java.sql.*;
import java.io.*;
import oracle.jdbc.*;
public class GenericDrop
{
  public static void dropIt(String object_type, String object_name)
                                                         throws SQLException
  {
    // Connect to Oracle using JDBC driver
    Connection conn = DriverManager.getConnection("jdbc:default:connection:");
    // Build SQL statement
    String sql = "DROP " + object_type + " " + object_name;
    try 
    {
      Statement stmt = conn.createStatement();
      stmt.executeUpdate(sql);
      stmt.close();
    }
    catch (SQLException e)
    {
      System.err.println(e.getMessage());
    }
  }
}
GenericDropクラスにはdropIt()という名前の1つのメソッドがあり、このメソッドはあらゆる種類のスキーマ・オブジェクトを削除します。たとえば、引数tableおよびemployeesをdropIt()に渡すと、メソッドはデータベース表employeesをスキーマから削除します。
                     
dropIt()メソッドのコール仕様は次のとおりです。
                     
CREATE OR REPLACE PROCEDURE drop_it (obj_type VARCHAR2, obj_name VARCHAR2) AS LANGUAGE JAVA NAME 'GenericDrop.dropIt(java.lang.String, java.lang.String)';
Stringに対する参照は完全に修飾する必要があることに注意してください。java.langパッケージはJavaプログラムで自動的に使用できますが、コール仕様で明示的に名前を付ける必要があります。
                     
例7-2 main()メソッドの公開
通常、Java名とコール仕様パラメータは対応する必要があります。ただし、この規則はmain()メソッドには適用されません。そのString[]パラメータは、複数のCHARまたはVARCHAR2のコール仕様パラメータにマッピングできます。引数を表示する次のクラスのmain()メソッドについて考えます。
                     
public class EchoInput
{
  public static void main (String[] args)
  {
    for (int i = 0; i < args.length; i++)
      System.out.println(args[i]);
  }
}
main()を公開するには、次のコール仕様を記述します。
                     
CREATE OR REPLACE PROCEDURE echo_input(s1 VARCHAR2, s2 VARCHAR2, s3 VARCHAR2) AS LANGUAGE JAVA NAME 'EchoInput.main(java.lang.String[])';
コール仕様パラメータに制約(精度、サイズおよびNOT NULLなど)を課すことはできません。そのため、VARCHAR2パラメータの最大サイズは指定できません。ただし、VARCHAR2変数の最大サイズを次のように指定する必要があります。
                     
DECLARE last_name VARCHAR2(20); -- size constraint required
例7-3 整数値を戻すメソッドの公開
次の例では、指定したデータベース表の行数を戻すrowCount()メソッドが公開されます。
                     
import java.sql.*;
import java.io.*;
import oracle.jdbc.*;
public class RowCounter
{
  public static int rowCount (String tabName) throws SQLException
  {
    Connection conn = DriverManager.getConnection("jdbc:default:connection:");
    String sql = "SELECT COUNT(*) FROM " + tabName;
    int rows = 0;
    try
    {
      Statement stmt = conn.createStatement();
      ResultSet rset = stmt.executeQuery(sql);
      while (rset.next())
      {
        rows = rset.getInt(1);
      }
      rset.close();
      stmt.close();
    }
    catch (SQLException e)
    {
      System.err.println(e.getMessage());
    }
    return rows;
  }
}
コール仕様では、NUMBERのサブタイプ(INTEGER、REALおよびPOSITIVEなど)が許可されていません。そのため、次のコール仕様では、戻り型はNUMBERであり、INTEGERではありません。
                     
CREATE FUNCTION row_count (tab_name VARCHAR2) RETURN NUMBER AS LANGUAGE JAVA NAME 'RowCounter.rowCount(java.lang.String) return int';
例7-4 引数の値を切り替えるメソッドの公開
引数の値を切り替える、次のSwapperクラスのswap()メソッドについて考えます。
                     
public class Swapper
{
  public static void swap (int[] x, int[] y)
  {
    int hold = x[0];
    x[0] = y[0];
    y[0] = hold;
  }
}
コール仕様によって、swap()メソッドがコール仕様swap()として公開されます。値を渡して戻す必要があるため、このコール仕様ではIN OUT仮パラメータが宣言されます。すべてのコール仕様のOUTパラメータおよびIN OUTパラメータを、Java配列パラメータにマッピングする必要があります。
                     
CREATE PROCEDURE swap (x IN OUT NUMBER, y IN OUT NUMBER) AS LANGUAGE JAVA NAME 'Swapper.swap(int[], int[])';
注意:
Javaメソッドとそのコール仕様には同じ名前を設定できます。