c:\Users\じぶん

技術ネタ半分、日記半分ですかね。

PL/SQL以外のストアドプロシージャ その2

Java言語でOracleのストアドプロシージャを作ってみます。

どんな言語を使うときも、最初はやっぱり文字列を画面に表示させるところからやってみましょう。いわゆる「ハローワールド」というやつです。

Javaのサンプルコードは以下になります。(HelloOracle.java)

public class HelloOracle {
   public static String hello() {
    return "hello";
  }
  public static String hello(String name) {
    return "hello," + name;
  }
}

HelloOracleというクラスにhelloメソッドが引数無し版と引数あり版の2種類存在します。引数が無ければ「hello」と引数があれば「hello,[引数]」を返します。見ての通り…ですね。

Oracle DatabaseのJVMから呼び出し可能なJavaプログラムはインスタンス化…つまり、newせずに使えるクラス・メソッドである必要があります。このためhelloは「public static」…外から見える静的メソッドとしています。

他のJavaプログラムからこのメソッドを呼び出しするときは、newせずにString helloReturn = HelloOracle.hello();な感じで使えます。この場合helloReturn変数に「hello」が入ります。

まずは、このJavaプログラムをOracle Databaseに登録する必要があります。 登録方法は幾つかありますが、今回はloadjavaというツールで登録してみます。 これはOracleクライアントと共にインストールされるツールで、Oracle homeのbinディレクトリに含まれます。

使い方は簡単です。

loadjava -user [ユーザ]/[パスワード]@[TNS接続文字] [対象javaソース]

です。具体的には

loadjava -user DBUSER/DBPASS@ORCL HelloOracle.java

といった感じですね。正常に登録された場合、何のメッセージも無くコマンドが終了します。このあたりが不親切ですよね。

javaソースをloadjavaツールでロードするとOracle Databaseに含まれるjavac(コンパイラ)でコンパイルされ、該当ユーザのjavaプログラムとして登録されます。ちなみに、javaソースでは無くコンパイル後のclassファイルもしくはjarファイルなどをロードすることも可能です。(この場合はJ2SE5.0などロード先のJVMに合ったバイナリにしておく必要あり)

登録されたら、次はSQLPL/SQLから呼べるようにするためJavaメソッドPL/SQLを紐付けます。ここがややこしくて面倒ですが「そういうもの」と割り切って進めます。

まず、引数無しの方から…

CREATE OR REPLACE FUNCTION HELLO_ONLY RETURN VARCHAR2
AS LANGUAGE JAVA
NAME 'HelloOracle.hello() return java.lang.String';
/

と、HELLO_ONLYというファンクションをCREATEします。引数無し、戻り値が文字列(VARCHAR2)の関数で、AS句と続くNAME句でJAVAメソッドと対応づけます。これによりメソッドと関数が

HelloOracle.hello()←→HELLO_ONLY

で紐付き、さらに戻り値が

java.lang.String←→VARCHAR2

の対応付けになります。この状態で実行してみると、

SQL> select hello_only from dual;

HELLO_ONLY
---------------
hello

と文字列helloがselect文で返るようになりました。 HELLO_ONLY関数からJVMを介してHeloOracleクラスのhello()メソッドを呼んだわけです。

引き続き、引数有り版のPL/SQLファンクションを

CREATE OR REPLACE FUNCTION DBUSER.HELLO_NAME(callName VARCHAR2) RETURN VARCHAR2
AS LANGUAGE JAVA
NAME 'HelloOracle.hello(java.lang.String) return java.lang.String';
/

のように、HELLO_NAME(文字列)として呼べる格好のファンクションでCREATEしてみます。これによりメソッドと関数・引数・戻り値が

関数:HelloOracle.hello←→HELLO_NAME

引数:(java.lang.String)←→(callName VARCHAR2)

戻り値:java.lang.String←→VARCHAR2

となる対応ができました。実行結果は

SQL> select hello_name('Oracle') from dual;

HELLO_NAME('ORACLE')
---------------
hello,Oracle

hello,に続いてSQLで引き渡しした文字列が含まれていますね。 SQLで指定した文字列「Oracle」がJVMを介してクラスメソッドに渡り、戻り値に反映して返ってきた…という訳です。