Autonomous DatabaseでJavaストアードプロシージャを試してみた

## はじめに
Oracle Autonomous Database (adb) では Java ストアードプロシージャも利用可能です。
この記事ではadb上でJavaストアドを登録し、呼び出してみる手順を実際の例付きで紹介します。


## 前提条件

* adbのWalletが取得済み
* adbに接続可能な環境
* loadjavaを実行するLinuxマシン or クライアントマシン

## 手順

### adbのjava vm起動


デフォルトではJVMが有効になっていないので下記SQLを実行後、adbを再起動します。
```plsql
BEGIN
   DBMS_CLOUD_ADMIN.ENABLE_FEATURE(
       feature_name => 'JAVAVM' );
END;
/
```



再起動後、SQLを実行してJAVAVMレコードが出てくればOK！

```sql:
SELECT status, version FROM DBA_REGISTRY WHERE comp_id = 'JAVAVM';
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846649/3cab2e0f-0d14-40c8-8208-d7f168d7ae39.png)



公式ページはこちら：

https://docs.oracle.com/ja-jp/iaas/autonomous-database-serverless/doc/dbms-cloud-admin.html#ADBSB-GUID-D9B49530-0AD8-46F4-9E6D-2E3B1D80DCC6


### jar準備
登録したいjarを作成します。今回はただDBMS_OUTPUTで文字を出力するだけのサンプルです。

```java:MyHello.java
package com.oracle.test;

import java.sql.CallableStatement;
import java.sql.Connection;

public class MyHello {
	public static void hello() {
		try {
			Connection conn = java.sql.DriverManager.getConnection("jdbc:default:connection:");
			CallableStatement cs = conn.prepareCall("{call dbms_output.put_line(?)}");
			cs.setString(1, "Hello from Java Stored Procedure via DBMS_OUTPUT!");
			cs.execute();
			cs.close();
			conn.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
```

### loadjava準備

先ほど作成したMyHello.jarをadbに登録していきます。

adbにjarを登録する概要については下記リンクに記述があります。


https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/autonomous-oracle-java.html#GUID-64BBF537-2884-444C-AAF4-7D1A7B723253


 
> 次の点に注意してください：
> 
> - ロードする Java コードは、OS コールやネットワークコールを呼び出すことはできません。
> 
> - サーバー側の `loadjava`（つまり `dbms_java.loadjava` プロシージャの呼び出し）はサポートされていません。`dbms_java.loadjava` プロシージャは Oracle JVM が動作するデータベース・サーバーのファイルシステムへアクセスしますが、これは Autonomous Database では許可されていません。そのため、Java アプリケーション内から `dbms_java.loadjava` プロシージャを呼び出すことはサポートされていません。


つまりdbms_java.loadjavaはだめで、クライアントのloadjavaコマンドを使用してjarを登録します。
loadjavaコマンドは通常のJDKには含まれておらず下記からclient_homeをインストールします。


https://www.oracle.com/database/technologies/oracle21c-linux-downloads.html


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846649/a26ddd06-7ab0-4a33-a178-a697c6ce395d.png)


### その他準備

Walletにあるsqlnet.oraのdirectoryを編集します。
※ client側loadjavaコマンドはこのWalletを参照してADBに安全に接続する必要があるため、正しいWalletパスを指定します
```
WALLET_LOCATION = (SOURCE = (METHOD = file) (METHOD_DATA = (DIRECTORY=/home/opc/Wallet)))
SSL_SERVER_DN_MATCH = yes
```

先ほど落としたclientにもojdbc8.jarはあるのですが、うまくadbに接続できなかったので下記URLからojdbc8-full.tar.gzをDLし、classpathに通して使用しています。

https://www.oracle.com/jp/database/technologies/appdev/jdbc-downloads.html


### jar登録

```shell
/home/opc/client/jdk/bin/java \
  -cp "/home/opc/ojdbc8/ojdbc8.jar:/home/opc/ojdbc8/ucp.jar:/home/opc/ojdbc8/oraclepki.jar:/home/opc/client/jlib/osdt_core.jar:/home/opc/client/jlib/osdt_cert.jar:/home/opc/client/javavm/lib/aurora.zip" \
  oracle.aurora.server.tools.loadjava.LoadJavaMain \
  -thin \
  -user "user/password@xxxx_tp" \
  -resolve \
  -verbose \
  /home/opc/MyHello.jar
```

実行後、下記で確認

```sql
SELECT * FROM user_objects WHERE object_type LIKE 'JAVA%';
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846649/805bd10c-8471-43e9-a3c4-16af0cfe6888.png)

### 動作確認

プロシージャを登録します。

```plsql
CREATE OR REPLACE PROCEDURE call_myhello AS
LANGUAGE JAVA
NAME 'com.oracle.test.MyHello.hello()';
/
```

```plsql
BEGIN
    call_myhello;
END;
/
```

出力を確認できました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846649/5ea7ae2d-414f-4546-869e-6071a9c94c86.png)


## まとめ

- ADBでもJavaストアードプロシージャが利用可能
- ADBでは server-side dbms_java.loadjava は使えない → client loadjava を利用
- Wallet や JDBC driver の設定に注意

今回のサンプルは非常に簡単なものでしたが、実際にはJDBC経由でDBアクセスやロジック実装も可能です。
用途に応じてぜひ活用してみてください！