2014年12月29日月曜日

Javaからのストアド呼出(TYPE RECORD)方法

ハマりました。
と、言うよりJava(JDK)とOracleを知らなすぎだっただけかも知れません。
JavaからOracleのストアドを呼び出すのは簡単なのですがストアド側の引数でTYPE RECORD型に対して引数として渡せないんです。

ネットの検索の仕方が悪いのか全く情報が見つからない。
同じようなことで苦労している人は居ないのだろうか?それとも常識すぎるのか?
今回自分がJabaからOracleのストアドを呼出するの初めてでOracleの知識も少ないせいかな?

ストアドはこんな感じです。(あくまでも参考ですので…)

/* レコード型定義 */
type TYPE_TEST_RECORD is record(
 numFIELD1 TEST.FIELD1%type
, numFIELD2 TEST.FIELD2%type,
 numFIELD3 TEST.FIELD3%type
);
/* PL/SQL表定義 */
type TYPE_TEST is table of TYPE_TEST_RECORD index by binary_integer;
/* ストアドI/F */
PROCEDURE ProcTEST (
 numRETURN_STS OUT NUMBER, /* リターンステータス */
 numPROCESS_CD IN NUMBER, /* 処理区分 */
 usrTYPE_io IN OUT TYPE_TEST /* データ格納領域 */
);

これをJavaのJDKのthinドライバから呼び出すことが出来ないんです。
TYPE_TESTへ値を渡せない。
Object型等色々試しても一向に拉致が空きませんでした。


そのため、いろいろ調べてみるとJPublisherなるものを使用すれば動作させることが出来るとOracleのページに記載があり調べてみたのだがよくわからん。
JDBCのOCIドライバにすれば出来るんじゃないの?なんて記載も見つけたが…
同じ箇所にストアドの中でTYPE RECORD型に値を設定しなおせば大丈夫との記載も。あまり推奨されていないようだが。

ストアド経由で更新処理だけを行うので簡単に済ませたい。
試しに以下のようにしてストアドの呼出関数を1枚かぶせて見たところ上手く行った。

/* ストアドI/F(Java用) */
PROCEDURE ProcTESTJ (
 numRETURN_STS OUT NUMBER, /* リターンステータス */
 numPROCESS_CD IN NUMBER, /* 処理区分 */
 numFIELD1 IN NUMBER,
 numFIELD2 IN NUMBER,
 numFIELD3 IN NUMBER );
PROCEDURE ProcTESTJ (
 numRETURN_STS OUT NUMBER, /* リターンステータス */
 numPROCESS_CD IN NUMBER, /* 処理区分 */
 numFIELD1 IN NUMBER,
 numFIELD2 IN NUMBER,
 numFIELD3 IN NUMBER
)
 IS
 test_rec TYPE_TEST ;
BEGIN
 test_rec(1).numFIELD1 = numFIELD1 ;
 test_rec(1).numFIELD2 = numFIELD2 ;
 test_rec(1).numFIELD3 = numFIELD3 ;
 ProcTEST (
  numRETURN_STS, /* リターンステータス */
  numPROCESS_CD, /* 処理区分 */
  test_rec /* データ格納領域 */ );
 END ProcTESTJ;

Javaでの呼出はTYPE RECORD型のメンバ数が増えると面倒だがこれで何とか出来る。

Java側はこんな感じです。
第一引数にリターン値が帰ってきます。

String sql="{call ProcTEST(?, ?, ?, ?, ?) }" ;
connection = DriverManager.getConnection(url, userid, password);
OracleCallableStatement callableStatement =    
                       (OracleCallableStatement)connection.prepareCall(sql); callableStatement.registerOutParameter( 1, java.sql.Types.INTEGER) ;
callableStatement.setInt( 2, 1) ;
callableStatement.setInt( 3, field1) ;
callableStatement.setInt( 4, field2) ;
callableStatement.setInt( 5, field3) ;
callableStatement.executeUpdate() ;
returnSts = callableStatement.getInt(1);

もっと良い方法もあると思いますが、JavaからストアドのTYPE RECORD型へ値を渡す際の参考になればと思います。
特にリプレース案件などでストアド使っているシステムをJavaに置き換えるなんて時に同じ現象にぶち当たる人いそうなんだけけどね。